mirror of
https://github.com/andatoshiki/toshiki-notebook.git
synced 2026-06-06 09:16:45 +00:00
259 lines
144 KiB
HTML
259 lines
144 KiB
HTML
<!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.1276ae12.css" as="style">
|
||
<script type="module" src="/assets/app.da2b9cf1.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.ade46834.js">
|
||
<link rel="modulepreload" href="/assets/chunks/theme.2274efad.js">
|
||
<link rel="modulepreload" href="/assets/chunks/s3_bucket_filelist.89f3f384.js">
|
||
<link rel="modulepreload" href="/assets/development_aws_handson-serverless.md.d45efc0b.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="/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's Note">
|
||
<meta property="og:description" content="Toshiki's web notebook served via Vitepress!">
|
||
<meta property="og:site" content="https://note.toshiki.dev">
|
||
<meta property="og:site_name" content="Toshiki'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="true" defer="true" data-website-id="86de8554-d4c9-4f2b-b62a-068b71241048" src="https://umami.toshiki.dev/umami.js"></script>
|
||
<script id="check-dark-light">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
|
||
</head>
|
||
<body>
|
||
<div id="app"><div class="Layout" data-v-83f63849><!--[--><!--]--><!--[--><span tabindex="-1" data-v-0eca8f1e></span><a href="#VPContent" class="VPSkipLink visually-hidden" data-v-0eca8f1e> Skip to content </a><!--]--><!----><header class="VPNav" data-v-83f63849 data-v-999a1a39><div class="VPNavBar has-sidebar" data-v-999a1a39 data-v-e99cf6bd><div class="container" data-v-e99cf6bd><div class="title" data-v-e99cf6bd><div class="VPNavBarTitle has-sidebar" data-v-e99cf6bd data-v-a8886b70><a class="title" href="/" data-v-a8886b70><!--[--><!--]--><!--[--><img class="VPImage logo" src="/logos/logo.png" alt data-v-164d1caf><!--]--><!--[-->Toshiki's Note<!--]--><!--[--><!--]--></a></div></div><div class="content" data-v-e99cf6bd><div class="curtain" data-v-e99cf6bd></div><div class="content-body" data-v-e99cf6bd><!--[--><!--]--><div class="VPNavBarSearch search" style="--vp-meta-key:'Meta';" data-v-e99cf6bd><!--[--><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-e99cf6bd data-v-1817056a><span id="main-nav-aria-label" class="visually-hidden" data-v-1817056a>Main Navigation</span><!--[--><!--[--><a class="VPLink link VPNavBarMenuLink" href="/development/" tabindex="0" data-v-1817056a data-v-f28b94cc data-v-075865b7><!--[-->Development<!--]--><!----></a><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-1817056a data-v-4c03a652><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-4c03a652><span class="text" data-v-4c03a652><!----> Academic <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-4c03a652><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-4c03a652><div class="VPMenu" data-v-4c03a652 data-v-da053c30><div class="items" data-v-da053c30><!--[--><!--[--><div class="VPMenuGroup" data-v-da053c30 data-v-2e982fbb><p class="title" data-v-2e982fbb>K-12</p><!--[--><!--[--><div class="VPMenuLink" data-v-2e982fbb data-v-6f715184><a class="VPLink link" href="/academic/chemistry/index" data-v-6f715184 data-v-075865b7><!--[-->Chemistry<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2e982fbb data-v-6f715184><a class="VPLink link" href="/discrete-math/index" data-v-6f715184 data-v-075865b7><!--[-->Discrete Math.<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2e982fbb data-v-6f715184><a class="VPLink link" href="/academic/literature/index" data-v-6f715184 data-v-075865b7><!--[-->Literature<!--]--><!----></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuGroup" data-v-da053c30 data-v-2e982fbb><p class="title" data-v-2e982fbb>Tools</p><!--[--><!--[--><div class="VPMenuLink" data-v-2e982fbb data-v-6f715184><a class="VPLink link" href="/academic/physics/ipho-formulas-jpn/1" data-v-6f715184 data-v-075865b7><!--[-->Formulas for IPhO JPN.<!--]--><!----></a></div><!--]--><!--]--></div><!--]--><!--[--><div class="VPMenuLink" data-v-da053c30 data-v-6f715184><span class="VPLink" data-v-6f715184 data-v-075865b7><!--[--><!--]--><!----></span></div><!--]--><!--[--><div class="VPMenuLink" data-v-da053c30 data-v-6f715184><span class="VPLink" data-v-6f715184 data-v-075865b7><!--[--><!--]--><!----></span></div><!--]--><!--[--><div class="VPMenuLink" data-v-da053c30 data-v-6f715184><span class="VPLink" data-v-6f715184 data-v-075865b7><!--[--><!--]--><!----></span></div><!--]--><!--[--><div class="VPMenuLink" data-v-da053c30 data-v-6f715184><span class="VPLink" data-v-6f715184 data-v-075865b7><!--[--><!--]--><!----></span></div><!--]--><!--[--><div class="VPMenuLink" data-v-da053c30 data-v-6f715184><span class="VPLink" data-v-6f715184 data-v-075865b7><!--[--><!--]--><!----></span></div><!--]--><!--[--><div class="VPMenuLink" data-v-da053c30 data-v-6f715184><span class="VPLink" data-v-6f715184 data-v-075865b7><!--[--><!--]--><!----></span></div><!--]--><!--[--><div class="VPMenuLink" data-v-da053c30 data-v-6f715184><span class="VPLink" data-v-6f715184 data-v-075865b7><!--[--><!--]--><!----></span></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-1817056a data-v-4c03a652><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-4c03a652><span class="text" data-v-4c03a652><!----> Application <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-4c03a652><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-4c03a652><div class="VPMenu" data-v-4c03a652 data-v-da053c30><div class="items" data-v-da053c30><!--[--><!--[--><div class="VPMenuGroup" data-v-da053c30 data-v-2e982fbb><p class="title" data-v-2e982fbb>Personal projects</p><!--[--><!--[--><div class="VPMenuLink" data-v-2e982fbb data-v-6f715184><a class="VPLink link" href="/application/markdown-it-katex/how-to-use" data-v-6f715184 data-v-075865b7><!--[-->markdown-it-katex<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-2e982fbb data-v-6f715184><a class="VPLink link" href="/application/vitepress-plugin-shiki-twoslash/index" data-v-6f715184 data-v-075865b7><!--[-->vitepress-plugin-shiki-twoslash<!--]--><!----></a></div><!--]--><!--]--></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--[--><div class="VPFlyout VPNavBarMenuGroup" data-v-1817056a data-v-4c03a652><button type="button" class="button" aria-haspopup="true" aria-expanded="false" data-v-4c03a652><span class="text" data-v-4c03a652><!----> Save <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="text-icon" data-v-4c03a652><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-4c03a652><div class="VPMenu" data-v-4c03a652 data-v-da053c30><div class="items" data-v-da053c30><!--[--><!--[--><div class="VPMenuLink" data-v-da053c30 data-v-6f715184><a class="VPLink link" href="/save/reading/index" data-v-6f715184 data-v-075865b7><!--[-->Reading<!--]--><!----></a></div><!--]--><!--[--><div class="VPMenuLink" data-v-da053c30 data-v-6f715184><a class="VPLink link" href="/academic/vocabulary/index" data-v-6f715184 data-v-075865b7><!--[-->Vocabulary<!--]--><!----></a></div><!--]--><!--]--></div><!--[--><!--]--></div></div></div><!--]--><!--]--></nav><!----><div class="VPNavBarAppearance appearance" data-v-e99cf6bd data-v-72c0c02a><label title="toggle dark mode" data-v-72c0c02a data-v-cb74fac6><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" aria-checked="false" data-v-cb74fac6 data-v-9f7dbbcf><span class="check" data-v-9f7dbbcf><span class="icon" data-v-9f7dbbcf><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-cb74fac6><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-cb74fac6><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></label></div><div class="VPSocialLinks VPNavBarSocialLinks social-links" data-v-e99cf6bd data-v-268ff66d data-v-65dbf981><!--[--><a class="VPSocialLink" href="https://github.com/andatoshiki" aria-label="github" target="_blank" rel="noopener" data-v-65dbf981 data-v-2d45784b><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" href="https://twitter.com/andatoshiki" aria-label="twitter" target="_blank" rel="noopener" data-v-65dbf981 data-v-2d45784b><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></svg></a><!--]--></div><div class="VPFlyout VPNavBarExtra extra" data-v-e99cf6bd data-v-67546bb2 data-v-4c03a652><button type="button" class="button" aria-haspopup="true" aria-expanded="false" aria-label="extra navigation" data-v-4c03a652><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="icon" data-v-4c03a652><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-4c03a652><div class="VPMenu" data-v-4c03a652 data-v-da053c30><!----><!--[--><!--[--><!----><div class="group" data-v-67546bb2><div class="item appearance" data-v-67546bb2><p class="label" data-v-67546bb2>Appearance</p><div class="appearance-action" data-v-67546bb2><label title="toggle dark mode" data-v-67546bb2 data-v-cb74fac6><button class="VPSwitch VPSwitchAppearance" type="button" role="switch" aria-checked="false" data-v-cb74fac6 data-v-9f7dbbcf><span class="check" data-v-9f7dbbcf><span class="icon" data-v-9f7dbbcf><!--[--><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="sun" data-v-cb74fac6><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-cb74fac6><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></label></div></div></div><div class="group" data-v-67546bb2><div class="item social-links" data-v-67546bb2><div class="VPSocialLinks social-links-list" data-v-67546bb2 data-v-65dbf981><!--[--><a class="VPSocialLink" href="https://github.com/andatoshiki" aria-label="github" target="_blank" rel="noopener" data-v-65dbf981 data-v-2d45784b><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" href="https://twitter.com/andatoshiki" aria-label="twitter" target="_blank" rel="noopener" data-v-65dbf981 data-v-2d45784b><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Twitter</title><path d="M23.953 4.57a10 10 0 01-2.825.775 4.958 4.958 0 002.163-2.723c-.951.555-2.005.959-3.127 1.184a4.92 4.92 0 00-8.384 4.482C7.69 8.095 4.067 6.13 1.64 3.162a4.822 4.822 0 00-.666 2.475c0 1.71.87 3.213 2.188 4.096a4.904 4.904 0 01-2.228-.616v.06a4.923 4.923 0 003.946 4.827 4.996 4.996 0 01-2.212.085 4.936 4.936 0 004.604 3.417 9.867 9.867 0 01-6.102 2.105c-.39 0-.779-.023-1.17-.067a13.995 13.995 0 007.557 2.209c9.053 0 13.998-7.496 13.998-13.985 0-.21 0-.42-.015-.63A9.935 9.935 0 0024 4.59z"/></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-e99cf6bd data-v-2314de5a><span class="container" data-v-2314de5a><span class="top" data-v-2314de5a></span><span class="middle" data-v-2314de5a></span><span class="bottom" data-v-2314de5a></span></span></button></div></div></div></div><!----></header><div class="VPLocalNav" data-v-83f63849 data-v-fa4746c0><button class="menu" aria-expanded="false" aria-controls="VPSidebarNav" data-v-fa4746c0><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="menu-icon" data-v-fa4746c0><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-fa4746c0>Menu</span></button><div class="VPLocalNavOutlineDropdown" style="--vp-vh:0px;" data-v-fa4746c0 data-v-f8dbb575><button data-v-f8dbb575>Return to top</button><!----></div></div><aside class="VPSidebar" data-v-83f63849 data-v-0e47c5d5><div class="curtain" data-v-0e47c5d5></div><nav class="nav" id="VPSidebarNav" aria-labelledby="sidebar-aria-label" tabindex="-1" data-v-0e47c5d5><span class="visually-hidden" id="sidebar-aria-label" data-v-0e47c5d5> Sidebar Navigation </span><!--[--><!--]--><!--[--><div class="group" data-v-0e47c5d5><section class="VPSidebarItem level-0 collapsible" data-v-0e47c5d5 data-v-0cc45b6b><div class="item" role="button" tabindex="0" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><h2 class="text" data-v-0cc45b6b>Notes & Issues</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-0cc45b6b><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-0cc45b6b><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-0cc45b6b><!--[--><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/file-naming-convention" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>File Naming Convention</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/rclone-for-r2" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>RClone for R2</p><!--]--><!----></a><!----></div><!----></div><!--]--></div></section></div><div class="group" data-v-0e47c5d5><section class="VPSidebarItem level-0 collapsible has-active" data-v-0e47c5d5 data-v-0cc45b6b><div class="item" role="button" tabindex="0" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><h2 class="text" data-v-0cc45b6b>コードで学ぶAWS入門</h2><div class="caret" role="button" aria-label="toggle section" tabindex="0" data-v-0cc45b6b><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" viewbox="0 0 24 24" class="caret-icon" data-v-0cc45b6b><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-0cc45b6b><!--[--><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/index" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>背景</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/main" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>はじめに!</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/cloud" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>クラウド概論</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/aws-get-started" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>AWS 入門</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/handson-ec2" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>Hands-on 1: 初めての EC2 インスタンスを起動する</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/scientific-computing" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>クラウドで行う科学計算・機械学習</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/handson-ec2" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>Hands-on 2: AWS でディープラーニングを実践</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/docker-system" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>Docker 入門</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/handson-qabot" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>Hands-on 3: AWS で自動質問回答ボットを走らせる</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/aws-batch" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>Hands-on 4: AWS Batch を使って機械学習のハイパーパラメータサーチを並列化する</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/webserver" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>Web サービスの作り方</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/serverless" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>Serverless architecture</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link is-active has-active" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/handson-serverless" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>Hands-on 5: サーバーレス入門</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/handson-bashoutter" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>Hands-on 6: Bashoutter</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/closing" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>まとめ</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/appendix" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>ppendix: 環境構築</p><!--]--><!----></a><!----></div><!----></div><div class="VPSidebarItem level-1 is-link" data-v-0cc45b6b data-v-0cc45b6b><div class="item" data-v-0cc45b6b><div class="indicator" data-v-0cc45b6b></div><a class="VPLink link link" href="/development/aws/acknowledgement" data-v-0cc45b6b data-v-075865b7><!--[--><p class="text" data-v-0cc45b6b>謝辞</p><!--]--><!----></a><!----></div><!----></div><!--]--></div></section></div><!--]--><!--[--><!--]--></nav></aside><div class="VPContent has-sidebar" id="VPContent" data-v-83f63849 data-v-bb292142><div class="VPDoc has-sidebar has-aside" data-v-bb292142 data-v-6c4a7022><!--[--><!--]--><div class="container" data-v-6c4a7022><div class="aside" data-v-6c4a7022><div class="aside-curtain" data-v-6c4a7022></div><div class="aside-container" data-v-6c4a7022><div class="aside-content" data-v-6c4a7022><div class="VPDocAside" data-v-6c4a7022 data-v-f77a9b1a><!--[--><!--]--><!--[--><!--]--><div class="VPDocAsideOutline" data-v-f77a9b1a data-v-ea95c6a2><div class="content" data-v-ea95c6a2><div class="outline-marker" data-v-ea95c6a2></div><div class="outline-title" data-v-ea95c6a2>TOC</div><nav aria-labelledby="doc-outline-aria-label" data-v-ea95c6a2><span class="visually-hidden" id="doc-outline-aria-label" data-v-ea95c6a2> Table of Contents for current page </span><ul class="root" data-v-ea95c6a2 data-v-74f66e6c><!--[--><!--]--></ul></nav></div></div><!--[--><!--]--><div class="spacer" data-v-f77a9b1a></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-6c4a7022><div class="content-container" data-v-6c4a7022><!--[--><!--]--><!----><main class="main" data-v-6c4a7022><div style="position:relative;" class="vp-doc _development_aws_handson-serverless" data-v-6c4a7022><div><h1 id="hands-on-5-サーバーレス入門" tabindex="-1">Hands-on #5: サーバーレス入門 <a class="header-anchor" href="#hands-on-5-サーバーレス入門" aria-label="Permalink to "Hands-on \#5: サーバーレス入門""></a></h1><p>前章ではサーバーレスアーキテクチャの概要の説明を行った. 本章では,ハンズオン形式でサーバーレスクラウドを実際に動かしながら,具体的な使用方法を学んでいこう. 今回のハンズオンでは Lambda, S3, DynamoDB の三つのサーバーレスクラウドの構成要素に触れていく. それぞれについて,短いチュートリアルを用意してある.</p><h2 id="lambda-ハンズオン" tabindex="-1">Lambda ハンズオン <a class="header-anchor" href="#lambda-ハンズオン" aria-label="Permalink to "Lambda ハンズオン""></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&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 solarized-dark vp-code-dark"><code><span class="line"><span style="color:#586E75;font-style:italic;">#</span></span>
|
||
<span class="line"><span style="color:#CB4B16;">FUNC</span><span style="color:#839496;"> </span><span style="color:#859900;">=</span><span style="color:#839496;"> </span><span style="color:#2AA198;">"""</span></span>
|
||
<span class="line"><span style="color:#2AA198;">import time</span></span>
|
||
<span class="line"><span style="color:#2AA198;">from random import choice, randint</span></span>
|
||
<span class="line"><span style="color:#2AA198;">def handler(event, context):</span></span>
|
||
<span class="line"><span style="color:#2AA198;"> time.sleep(randint(2,5))</span></span>
|
||
<span class="line"><span style="color:#2AA198;"> sushi = ["salmon", "tuna", "squid"]</span></span>
|
||
<span class="line"><span style="color:#2AA198;"> message = "Welcome to Cloud Sushi. Your order is " + choice(sushi)</span></span>
|
||
<span class="line"><span style="color:#2AA198;"> print(message)</span></span>
|
||
<span class="line"><span style="color:#2AA198;"> return message</span></span>
|
||
<span class="line"><span style="color:#2AA198;">"""</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#93A1A1;font-weight:bold;">class</span><span style="color:#839496;"> </span><span style="color:#CB4B16;">SimpleLambda</span><span style="color:#839496;">(</span><span style="color:#6C71C4;">core</span><span style="color:#839496;">.</span><span style="color:#6C71C4;">Stack</span><span style="color:#839496;">):</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#93A1A1;font-weight:bold;">def</span><span style="color:#839496;"> </span><span style="color:#268BD2;">__init__</span><span style="color:#839496;">(self, scope: core.App, name: </span><span style="color:#859900;">str</span><span style="color:#839496;">, </span><span style="color:#859900;">**</span><span style="color:#839496;">kwargs) -> </span><span style="color:#B58900;">None</span><span style="color:#839496;">:</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#859900;">super</span><span style="color:#839496;">().</span><span style="color:#268BD2;">__init__</span><span style="color:#839496;">(scope, name, </span><span style="color:#859900;">**</span><span style="color:#839496;">kwargs)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#586E75;font-style:italic;">#</span></span>
|
||
<span class="line"><span style="color:#839496;"> handler </span><span style="color:#859900;">=</span><span style="color:#839496;"> _lambda.Function(</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#268BD2;">self</span><span style="color:#839496;">, </span><span style="color:#2AA198;">'LambdaHandler'</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> runtime</span><span style="color:#859900;">=</span><span style="color:#839496;">_lambda.Runtime.</span><span style="color:#CB4B16;">PYTHON_3_7</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> code</span><span style="color:#859900;">=</span><span style="color:#839496;">_lambda.Code.from_inline(</span><span style="color:#CB4B16;">FUNC</span><span style="color:#839496;">),</span></span>
|
||
<span class="line"><span style="color:#839496;"> handler</span><span style="color:#859900;">=</span><span style="color:#2AA198;">"index.handler"</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> memory_size</span><span style="color:#859900;">=</span><span style="color:#D33682;">128</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> timeout</span><span style="color:#859900;">=</span><span style="color:#839496;">core.Duration.seconds(</span><span style="color:#D33682;">10</span><span style="color:#839496;">),</span></span>
|
||
<span class="line"><span style="color:#839496;"> dead_letter_queue_enabled</span><span style="color:#859900;">=</span><span style="color:#B58900;">True</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> )</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#93A1A1;font-style:italic;">#</span></span>
|
||
<span class="line"><span style="color:#CB4B16;">FUNC</span><span style="color:#657B83;"> </span><span style="color:#859900;">=</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">"""</span></span>
|
||
<span class="line"><span style="color:#2AA198;">import time</span></span>
|
||
<span class="line"><span style="color:#2AA198;">from random import choice, randint</span></span>
|
||
<span class="line"><span style="color:#2AA198;">def handler(event, context):</span></span>
|
||
<span class="line"><span style="color:#2AA198;"> time.sleep(randint(2,5))</span></span>
|
||
<span class="line"><span style="color:#2AA198;"> sushi = ["salmon", "tuna", "squid"]</span></span>
|
||
<span class="line"><span style="color:#2AA198;"> message = "Welcome to Cloud Sushi. Your order is " + choice(sushi)</span></span>
|
||
<span class="line"><span style="color:#2AA198;"> print(message)</span></span>
|
||
<span class="line"><span style="color:#2AA198;"> return message</span></span>
|
||
<span class="line"><span style="color:#2AA198;">"""</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#586E75;font-weight:bold;">class</span><span style="color:#657B83;"> </span><span style="color:#CB4B16;">SimpleLambda</span><span style="color:#657B83;">(</span><span style="color:#6C71C4;">core</span><span style="color:#657B83;">.</span><span style="color:#6C71C4;">Stack</span><span style="color:#657B83;">):</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#586E75;font-weight:bold;">def</span><span style="color:#657B83;"> </span><span style="color:#268BD2;">__init__</span><span style="color:#657B83;">(self, scope: core.App, name: </span><span style="color:#859900;">str</span><span style="color:#657B83;">, </span><span style="color:#859900;">**</span><span style="color:#657B83;">kwargs) -> </span><span style="color:#B58900;">None</span><span style="color:#657B83;">:</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#859900;">super</span><span style="color:#657B83;">().</span><span style="color:#268BD2;">__init__</span><span style="color:#657B83;">(scope, name, </span><span style="color:#859900;">**</span><span style="color:#657B83;">kwargs)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#93A1A1;font-style:italic;">#</span></span>
|
||
<span class="line"><span style="color:#657B83;"> handler </span><span style="color:#859900;">=</span><span style="color:#657B83;"> _lambda.Function(</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#268BD2;">self</span><span style="color:#657B83;">, </span><span style="color:#2AA198;">'LambdaHandler'</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> runtime</span><span style="color:#859900;">=</span><span style="color:#657B83;">_lambda.Runtime.</span><span style="color:#CB4B16;">PYTHON_3_7</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> code</span><span style="color:#859900;">=</span><span style="color:#657B83;">_lambda.Code.from_inline(</span><span style="color:#CB4B16;">FUNC</span><span style="color:#657B83;">),</span></span>
|
||
<span class="line"><span style="color:#657B83;"> handler</span><span style="color:#859900;">=</span><span style="color:#2AA198;">"index.handler"</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> memory_size</span><span style="color:#859900;">=</span><span style="color:#D33682;">128</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> timeout</span><span style="color:#859900;">=</span><span style="color:#657B83;">core.Duration.seconds(</span><span style="color:#D33682;">10</span><span style="color:#657B83;">),</span></span>
|
||
<span class="line"><span style="color:#657B83;"> dead_letter_queue_enabled</span><span style="color:#859900;">=</span><span style="color:#B58900;">True</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> )</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 秒のランダムな時間スリープした後,["salmon", "tuna", "squid"] のいずれかの文字列をランダムに選択し, "Welcome to Cloud Sushi. Your order is XXXX" (XXXX は選ばれた寿司のネタ) というメッセージをリターンする.</p></li><li><p>次に, Lambda に <1> で書いた関数を配置している. パラメータの意味は,文字どおりの意味なので難しくはないが,以下に解説する.</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="index.handler"</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 "デプロイ""></a></h3><p>デプロイの手順は,これまでのハンズオンとほとんど共通である. ここでは,コマンドのみ列挙する (<code>#</code> で始まる行はコメントである). それぞれの意味を忘れてしまった場合は,ハンズオン 1, 2 に戻って復習していただきたい. シークレットキーの設定も忘れずに (<a href="#aws_cli_install">???</a>).</p><div class="language-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#586E75;font-style:italic;"># プロジェクトのディレクトリに移動</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">cd</span><span style="color:#839496;"> </span><span style="color:#2AA198;">handson/serverless/lambda</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#586E75;font-style:italic;"># venv を作成し,依存ライブラリのインストールを行う</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">python3</span><span style="color:#839496;"> </span><span style="color:#CB4B16;">-m</span><span style="color:#839496;"> </span><span style="color:#2AA198;">venv</span><span style="color:#839496;"> </span><span style="color:#2AA198;">.env</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">source</span><span style="color:#839496;"> </span><span style="color:#2AA198;">.env/bin/activate</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">pip</span><span style="color:#839496;"> </span><span style="color:#2AA198;">install</span><span style="color:#839496;"> </span><span style="color:#CB4B16;">-r</span><span style="color:#839496;"> </span><span style="color:#2AA198;">requirements.txt</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#586E75;font-style:italic;"># デプロイを実行</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">cdk</span><span style="color:#839496;"> </span><span style="color:#2AA198;">deploy</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#93A1A1;font-style:italic;"># プロジェクトのディレクトリに移動</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">cd</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">handson/serverless/lambda</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#93A1A1;font-style:italic;"># venv を作成し,依存ライブラリのインストールを行う</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">python3</span><span style="color:#657B83;"> </span><span style="color:#CB4B16;">-m</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">venv</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">.env</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">source</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">.env/bin/activate</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">pip</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">install</span><span style="color:#657B83;"> </span><span style="color:#CB4B16;">-r</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">requirements.txt</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#93A1A1;font-style:italic;"># デプロイを実行</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">cdk</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">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 "Lambda 関数の実行""></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-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">python</span><span style="color:#839496;"> </span><span style="color:#2AA198;">invoke_one.py</span><span style="color:#839496;"> </span><span style="color:#2AA198;">XXXX</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">python</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">invoke_one.py</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">XXXX</span></span></code></pre><div class="line-numbers-wrapper" aria-hidden="true"><span class="line-number">1</span><br></div></div><p>すると, <code>"Welcome to Cloud Sushi. Your order is salmon"</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-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">python</span><span style="color:#839496;"> </span><span style="color:#2AA198;">invoke_many.py</span><span style="color:#839496;"> </span><span style="color:#2AA198;">XXXX</span><span style="color:#839496;"> </span><span style="color:#D33682;">100</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">python</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">invoke_many.py</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">XXXX</span><span style="color:#657B83;"> </span><span style="color:#D33682;">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-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">....................................................................................................</span></span>
|
||
<span class="line"><span style="color:#268BD2;">Submitted</span><span style="color:#839496;"> </span><span style="color:#D33682;">100</span><span style="color:#839496;"> </span><span style="color:#2AA198;">tasks</span><span style="color:#839496;"> </span><span style="color:#2AA198;">to</span><span style="color:#839496;"> </span><span style="color:#2AA198;">Lambda!</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">....................................................................................................</span></span>
|
||
<span class="line"><span style="color:#268BD2;">Submitted</span><span style="color:#657B83;"> </span><span style="color:#D33682;">100</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">tasks</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">to</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">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> の画面に戻り, "Monitoring" というタブがあるので,それをクリックする. すると, <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> で "Invocations" が関数が何度実行されたかを意味している. たしかに 100 回実行されていることがわかる. さらに, "Concurrent executions" は何個のタスクが同時に行われたかを示している. ここでは 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 "スタックの削除""></a></h3><p>最後にスタックを削除しよう. スタックを削除するには,次のコマンドを実行すればよい.</p><div class="language-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">cdk</span><span style="color:#839496;"> </span><span style="color:#2AA198;">destroy</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">cdk</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">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 "DynamoDB ハンズオン""></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&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 solarized-dark vp-code-dark"><code><span class="line"><span style="color:#93A1A1;font-weight:bold;">class</span><span style="color:#839496;"> </span><span style="color:#CB4B16;">SimpleDynamoDb</span><span style="color:#839496;">(</span><span style="color:#6C71C4;">core</span><span style="color:#839496;">.</span><span style="color:#6C71C4;">Stack</span><span style="color:#839496;">):</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#93A1A1;font-weight:bold;">def</span><span style="color:#839496;"> </span><span style="color:#268BD2;">__init__</span><span style="color:#839496;">(self, scope: core.App, name: </span><span style="color:#859900;">str</span><span style="color:#839496;">, </span><span style="color:#859900;">**</span><span style="color:#839496;">kwargs) -> </span><span style="color:#B58900;">None</span><span style="color:#839496;">:</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#859900;">super</span><span style="color:#839496;">().</span><span style="color:#268BD2;">__init__</span><span style="color:#839496;">(scope, name, </span><span style="color:#859900;">**</span><span style="color:#839496;">kwargs)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#839496;"> table </span><span style="color:#859900;">=</span><span style="color:#839496;"> ddb.Table(</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#268BD2;">self</span><span style="color:#839496;">, </span><span style="color:#2AA198;">"SimpleTable"</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#586E75;font-style:italic;">#</span></span>
|
||
<span class="line"><span style="color:#839496;"> partition_key</span><span style="color:#859900;">=</span><span style="color:#839496;">ddb.Attribute(</span></span>
|
||
<span class="line"><span style="color:#839496;"> name</span><span style="color:#859900;">=</span><span style="color:#2AA198;">"item_id"</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> type</span><span style="color:#859900;">=</span><span style="color:#839496;">ddb.AttributeType.</span><span style="color:#CB4B16;">STRING</span></span>
|
||
<span class="line"><span style="color:#839496;"> ),</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#586E75;font-style:italic;">#</span></span>
|
||
<span class="line"><span style="color:#839496;"> billing_mode</span><span style="color:#859900;">=</span><span style="color:#839496;">ddb.BillingMode.</span><span style="color:#CB4B16;">PAY_PER_REQUEST</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#586E75;font-style:italic;">#</span></span>
|
||
<span class="line"><span style="color:#839496;"> removal_policy</span><span style="color:#859900;">=</span><span style="color:#839496;">core.RemovalPolicy.</span><span style="color:#CB4B16;">DESTROY</span></span>
|
||
<span class="line"><span style="color:#839496;"> )</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#586E75;font-weight:bold;">class</span><span style="color:#657B83;"> </span><span style="color:#CB4B16;">SimpleDynamoDb</span><span style="color:#657B83;">(</span><span style="color:#6C71C4;">core</span><span style="color:#657B83;">.</span><span style="color:#6C71C4;">Stack</span><span style="color:#657B83;">):</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#586E75;font-weight:bold;">def</span><span style="color:#657B83;"> </span><span style="color:#268BD2;">__init__</span><span style="color:#657B83;">(self, scope: core.App, name: </span><span style="color:#859900;">str</span><span style="color:#657B83;">, </span><span style="color:#859900;">**</span><span style="color:#657B83;">kwargs) -> </span><span style="color:#B58900;">None</span><span style="color:#657B83;">:</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#859900;">super</span><span style="color:#657B83;">().</span><span style="color:#268BD2;">__init__</span><span style="color:#657B83;">(scope, name, </span><span style="color:#859900;">**</span><span style="color:#657B83;">kwargs)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#657B83;"> table </span><span style="color:#859900;">=</span><span style="color:#657B83;"> ddb.Table(</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#268BD2;">self</span><span style="color:#657B83;">, </span><span style="color:#2AA198;">"SimpleTable"</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#93A1A1;font-style:italic;">#</span></span>
|
||
<span class="line"><span style="color:#657B83;"> partition_key</span><span style="color:#859900;">=</span><span style="color:#657B83;">ddb.Attribute(</span></span>
|
||
<span class="line"><span style="color:#657B83;"> name</span><span style="color:#859900;">=</span><span style="color:#2AA198;">"item_id"</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> type</span><span style="color:#859900;">=</span><span style="color:#657B83;">ddb.AttributeType.</span><span style="color:#CB4B16;">STRING</span></span>
|
||
<span class="line"><span style="color:#657B83;"> ),</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#93A1A1;font-style:italic;">#</span></span>
|
||
<span class="line"><span style="color:#657B83;"> billing_mode</span><span style="color:#859900;">=</span><span style="color:#657B83;">ddb.BillingMode.</span><span style="color:#CB4B16;">PAY_PER_REQUEST</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#93A1A1;font-style:italic;">#</span></span>
|
||
<span class="line"><span style="color:#657B83;"> removal_policy</span><span style="color:#859900;">=</span><span style="color:#657B83;">core.RemovalPolicy.</span><span style="color:#CB4B16;">DESTROY</span></span>
|
||
<span class="line"><span style="color:#657B83;"> )</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">公式ドキュメンテーション "Core Components of Amazon DynamoDB"</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 "デプロイ""></a></h3><p>デプロイの手順は,これまでのハンズオンとほとんど共通である. ここでは,コマンドのみ列挙する (<code>#</code> で始まる行はコメントである). シークレットキーの設定も忘れずに (<a href="#aws_cli_install">???</a>).</p><div class="language-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#586E75;font-style:italic;"># プロジェクトのディレクトリに移動</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">cd</span><span style="color:#839496;"> </span><span style="color:#2AA198;">handson/serverless/dynamodb</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#586E75;font-style:italic;"># venv を作成し,依存ライブラリのインストールを行う</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">python3</span><span style="color:#839496;"> </span><span style="color:#CB4B16;">-m</span><span style="color:#839496;"> </span><span style="color:#2AA198;">venv</span><span style="color:#839496;"> </span><span style="color:#2AA198;">.env</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">source</span><span style="color:#839496;"> </span><span style="color:#2AA198;">.env/bin/activate</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">pip</span><span style="color:#839496;"> </span><span style="color:#2AA198;">install</span><span style="color:#839496;"> </span><span style="color:#CB4B16;">-r</span><span style="color:#839496;"> </span><span style="color:#2AA198;">requirements.txt</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#586E75;font-style:italic;"># デプロイを実行</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">cdk</span><span style="color:#839496;"> </span><span style="color:#2AA198;">deploy</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#93A1A1;font-style:italic;"># プロジェクトのディレクトリに移動</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">cd</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">handson/serverless/dynamodb</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#93A1A1;font-style:italic;"># venv を作成し,依存ライブラリのインストールを行う</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">python3</span><span style="color:#657B83;"> </span><span style="color:#CB4B16;">-m</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">venv</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">.env</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">source</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">.env/bin/activate</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">pip</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">install</span><span style="color:#657B83;"> </span><span style="color:#CB4B16;">-r</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">requirements.txt</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#93A1A1;font-style:italic;"># デプロイを実行</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">cdk</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">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 のページに行き,左のメニューバーから "Tables" を選択する. すると, <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> のような画面が表示されるはずだ. "Items" のタブをクリックすると,テーブルの中のレコードを確認できる. 現時点ではなにもデータを書き込んでいないので,空である.</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 "データの読み書き""></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 solarized-dark vp-code-dark"><code><span class="line"><span style="color:#859900;">import</span><span style="color:#839496;"> boto3</span></span>
|
||
<span class="line"><span style="color:#859900;">from</span><span style="color:#839496;"> uuid </span><span style="color:#859900;">import</span><span style="color:#839496;"> uuid4</span></span>
|
||
<span class="line"><span style="color:#839496;">ddb </span><span style="color:#859900;">=</span><span style="color:#839496;"> boto3.resource(</span><span style="color:#2AA198;">'dynamodb'</span><span style="color:#839496;">)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#93A1A1;font-weight:bold;">def</span><span style="color:#839496;"> </span><span style="color:#268BD2;">write_item</span><span style="color:#839496;">(table_name):</span></span>
|
||
<span class="line"><span style="color:#839496;"> table </span><span style="color:#859900;">=</span><span style="color:#839496;"> ddb.Table(table_name)</span></span>
|
||
<span class="line"><span style="color:#839496;"> table.put_item(</span></span>
|
||
<span class="line"><span style="color:#839496;"> Item</span><span style="color:#859900;">=</span><span style="color:#839496;">{</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#2AA198;">'item_id'</span><span style="color:#839496;">: </span><span style="color:#859900;">str</span><span style="color:#839496;">(uuid4()),</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#2AA198;">'first_name'</span><span style="color:#839496;">: </span><span style="color:#2AA198;">'John'</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#2AA198;">'last_name'</span><span style="color:#839496;">: </span><span style="color:#2AA198;">'Doe'</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#2AA198;">'age'</span><span style="color:#839496;">: </span><span style="color:#D33682;">25</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> }</span></span>
|
||
<span class="line"><span style="color:#839496;"> )</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#859900;">import</span><span style="color:#657B83;"> boto3</span></span>
|
||
<span class="line"><span style="color:#859900;">from</span><span style="color:#657B83;"> uuid </span><span style="color:#859900;">import</span><span style="color:#657B83;"> uuid4</span></span>
|
||
<span class="line"><span style="color:#657B83;">ddb </span><span style="color:#859900;">=</span><span style="color:#657B83;"> boto3.resource(</span><span style="color:#2AA198;">'dynamodb'</span><span style="color:#657B83;">)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#586E75;font-weight:bold;">def</span><span style="color:#657B83;"> </span><span style="color:#268BD2;">write_item</span><span style="color:#657B83;">(table_name):</span></span>
|
||
<span class="line"><span style="color:#657B83;"> table </span><span style="color:#859900;">=</span><span style="color:#657B83;"> ddb.Table(table_name)</span></span>
|
||
<span class="line"><span style="color:#657B83;"> table.put_item(</span></span>
|
||
<span class="line"><span style="color:#657B83;"> Item</span><span style="color:#859900;">=</span><span style="color:#657B83;">{</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#2AA198;">'item_id'</span><span style="color:#657B83;">: </span><span style="color:#859900;">str</span><span style="color:#657B83;">(uuid4()),</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#2AA198;">'first_name'</span><span style="color:#657B83;">: </span><span style="color:#2AA198;">'John'</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#2AA198;">'last_name'</span><span style="color:#657B83;">: </span><span style="color:#2AA198;">'Doe'</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#2AA198;">'age'</span><span style="color:#657B83;">: </span><span style="color:#D33682;">25</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> }</span></span>
|
||
<span class="line"><span style="color:#657B83;"> )</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> を実行してみよう. "XXXX" の部分を自分がデプロイしたテーブルの名前 (<code>SimpleDynamoDb</code> で始まる文字列) に置き換えたうえで,次のコマンドを実行する.</p><div class="language-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">python</span><span style="color:#839496;"> </span><span style="color:#2AA198;">simple_write.py</span><span style="color:#839496;"> </span><span style="color:#2AA198;">XXXX</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">python</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">simple_write.py</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">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 solarized-dark vp-code-dark"><code><span class="line"><span style="color:#859900;">import</span><span style="color:#839496;"> boto3</span></span>
|
||
<span class="line"><span style="color:#839496;">ddb </span><span style="color:#859900;">=</span><span style="color:#839496;"> boto3.resource(</span><span style="color:#2AA198;">'dynamodb'</span><span style="color:#839496;">)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#93A1A1;font-weight:bold;">def</span><span style="color:#839496;"> </span><span style="color:#268BD2;">scan_table</span><span style="color:#839496;">(table_name):</span></span>
|
||
<span class="line"><span style="color:#839496;"> table </span><span style="color:#859900;">=</span><span style="color:#839496;"> ddb.Table(table_name)</span></span>
|
||
<span class="line"><span style="color:#839496;"> items </span><span style="color:#859900;">=</span><span style="color:#839496;"> table.scan().get(</span><span style="color:#2AA198;">"Items"</span><span style="color:#839496;">)</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#268BD2;">print</span><span style="color:#839496;">(items)</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#859900;">import</span><span style="color:#657B83;"> boto3</span></span>
|
||
<span class="line"><span style="color:#657B83;">ddb </span><span style="color:#859900;">=</span><span style="color:#657B83;"> boto3.resource(</span><span style="color:#2AA198;">'dynamodb'</span><span style="color:#657B83;">)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#586E75;font-weight:bold;">def</span><span style="color:#657B83;"> </span><span style="color:#268BD2;">scan_table</span><span style="color:#657B83;">(table_name):</span></span>
|
||
<span class="line"><span style="color:#657B83;"> table </span><span style="color:#859900;">=</span><span style="color:#657B83;"> ddb.Table(table_name)</span></span>
|
||
<span class="line"><span style="color:#657B83;"> items </span><span style="color:#859900;">=</span><span style="color:#657B83;"> table.scan().get(</span><span style="color:#2AA198;">"Items"</span><span style="color:#657B83;">)</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#268BD2;">print</span><span style="color:#657B83;">(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("Items")</code> によって,テーブルの中にあるすべての要素を読みだしている.</p><p>次のコマンドで,このスクリプトを実行してみよう ("XXXX" の部分を正しく置き換えることを忘れずに).</p><div class="language-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">python</span><span style="color:#839496;"> </span><span style="color:#2AA198;">simple_read.py</span><span style="color:#839496;"> </span><span style="color:#2AA198;">XXXX</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">python</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">simple_read.py</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">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 "大量のデータの読み書き""></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-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">python</span><span style="color:#839496;"> </span><span style="color:#2AA198;">batch_rw.py</span><span style="color:#839496;"> </span><span style="color:#2AA198;">XXXX</span><span style="color:#839496;"> </span><span style="color:#2AA198;">write</span><span style="color:#839496;"> </span><span style="color:#D33682;">1000</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">python</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">batch_rw.py</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">XXXX</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">write</span><span style="color:#657B83;"> </span><span style="color:#D33682;">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-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">python</span><span style="color:#839496;"> </span><span style="color:#2AA198;">batch_rw.py</span><span style="color:#839496;"> </span><span style="color:#2AA198;">XXXX</span><span style="color:#839496;"> </span><span style="color:#2AA198;">search_under_age</span><span style="color:#839496;"> </span><span style="color:#D33682;">2</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">python</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">batch_rw.py</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">XXXX</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">search_under_age</span><span style="color:#657B83;"> </span><span style="color:#D33682;">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 "スタックの削除""></a></h3><p>DynamoDB で十分に遊ぶことができたら,忘れずにスタックを削除しよう.</p><p>これまでのハンズオンと同様,スタックを削除するには,次のコマンドを実行すればよい.</p><div class="language-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">cdk</span><span style="color:#839496;"> </span><span style="color:#2AA198;">destroy</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">cdk</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">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 "S3 ハンズオン""></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&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 solarized-dark vp-code-dark"><code><span class="line"><span style="color:#93A1A1;font-weight:bold;">class</span><span style="color:#839496;"> </span><span style="color:#CB4B16;">SimpleS3</span><span style="color:#839496;">(</span><span style="color:#6C71C4;">core</span><span style="color:#839496;">.</span><span style="color:#6C71C4;">Stack</span><span style="color:#839496;">):</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#93A1A1;font-weight:bold;">def</span><span style="color:#839496;"> </span><span style="color:#268BD2;">__init__</span><span style="color:#839496;">(self, scope: core.App, name: </span><span style="color:#859900;">str</span><span style="color:#839496;">, </span><span style="color:#859900;">**</span><span style="color:#839496;">kwargs) -> </span><span style="color:#B58900;">None</span><span style="color:#839496;">:</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#859900;">super</span><span style="color:#839496;">().</span><span style="color:#268BD2;">__init__</span><span style="color:#839496;">(scope, name, </span><span style="color:#859900;">**</span><span style="color:#839496;">kwargs)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#586E75;font-style:italic;"># S3 bucket to store data</span></span>
|
||
<span class="line"><span style="color:#839496;"> bucket </span><span style="color:#859900;">=</span><span style="color:#839496;"> s3.Bucket(</span></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#268BD2;">self</span><span style="color:#839496;">, </span><span style="color:#2AA198;">"bucket"</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> removal_policy</span><span style="color:#859900;">=</span><span style="color:#839496;">core.RemovalPolicy.</span><span style="color:#CB4B16;">DESTROY</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> auto_delete_objects</span><span style="color:#859900;">=</span><span style="color:#B58900;">True</span><span style="color:#839496;">,</span></span>
|
||
<span class="line"><span style="color:#839496;"> )</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#586E75;font-weight:bold;">class</span><span style="color:#657B83;"> </span><span style="color:#CB4B16;">SimpleS3</span><span style="color:#657B83;">(</span><span style="color:#6C71C4;">core</span><span style="color:#657B83;">.</span><span style="color:#6C71C4;">Stack</span><span style="color:#657B83;">):</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#586E75;font-weight:bold;">def</span><span style="color:#657B83;"> </span><span style="color:#268BD2;">__init__</span><span style="color:#657B83;">(self, scope: core.App, name: </span><span style="color:#859900;">str</span><span style="color:#657B83;">, </span><span style="color:#859900;">**</span><span style="color:#657B83;">kwargs) -> </span><span style="color:#B58900;">None</span><span style="color:#657B83;">:</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#859900;">super</span><span style="color:#657B83;">().</span><span style="color:#268BD2;">__init__</span><span style="color:#657B83;">(scope, name, </span><span style="color:#859900;">**</span><span style="color:#657B83;">kwargs)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#93A1A1;font-style:italic;"># S3 bucket to store data</span></span>
|
||
<span class="line"><span style="color:#657B83;"> bucket </span><span style="color:#859900;">=</span><span style="color:#657B83;"> s3.Bucket(</span></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#268BD2;">self</span><span style="color:#657B83;">, </span><span style="color:#2AA198;">"bucket"</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> removal_policy</span><span style="color:#859900;">=</span><span style="color:#657B83;">core.RemovalPolicy.</span><span style="color:#CB4B16;">DESTROY</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> auto_delete_objects</span><span style="color:#859900;">=</span><span style="color:#B58900;">True</span><span style="color:#657B83;">,</span></span>
|
||
<span class="line"><span style="color:#657B83;"> )</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 "デプロイ""></a></h3><p>デプロイの手順は,これまでのハンズオンとほとんど共通である. ここでは,コマンドのみ列挙する (<code>#</code> で始まる行はコメントである). シークレットキーの設定も忘れずに (<a href="#aws_cli_install">???</a>).</p><div class="language-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#586E75;font-style:italic;"># プロジェクトのディレクトリに移動</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">cd</span><span style="color:#839496;"> </span><span style="color:#2AA198;">handson/serverless/s3</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#586E75;font-style:italic;"># venv を作成し,依存ライブラリのインストールを行う</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">python3</span><span style="color:#839496;"> </span><span style="color:#CB4B16;">-m</span><span style="color:#839496;"> </span><span style="color:#2AA198;">venv</span><span style="color:#839496;"> </span><span style="color:#2AA198;">.env</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">source</span><span style="color:#839496;"> </span><span style="color:#2AA198;">.env/bin/activate</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">pip</span><span style="color:#839496;"> </span><span style="color:#2AA198;">install</span><span style="color:#839496;"> </span><span style="color:#CB4B16;">-r</span><span style="color:#839496;"> </span><span style="color:#2AA198;">requirements.txt</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#586E75;font-style:italic;"># デプロイを実行</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">cdk</span><span style="color:#839496;"> </span><span style="color:#2AA198;">deploy</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#93A1A1;font-style:italic;"># プロジェクトのディレクトリに移動</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">cd</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">handson/serverless/s3</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#93A1A1;font-style:italic;"># venv を作成し,依存ライブラリのインストールを行う</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">python3</span><span style="color:#657B83;"> </span><span style="color:#CB4B16;">-m</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">venv</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">.env</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">source</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">.env/bin/activate</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">pip</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">install</span><span style="color:#657B83;"> </span><span style="color:#CB4B16;">-r</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">requirements.txt</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#93A1A1;font-style:italic;"># デプロイを実行</span></span>
|
||
<span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">cdk</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">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 "データの読み書き""></a></h3><p>スタックのデプロイが完了したら,早速バケットにデータをアップロードしてみよう.</p><p>まずは,以下のコマンドを実行して, <code>tmp.txt</code> という仮のファイルを生成する.</p><div class="language-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">echo</span><span style="color:#839496;"> </span><span style="color:#2AA198;">"Hello world!"</span><span style="color:#839496;"> </span><span style="color:#859900;">>></span><span style="color:#839496;"> </span><span style="color:#2AA198;">tmp.txt</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">echo</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">"Hello world!"</span><span style="color:#657B83;"> </span><span style="color:#859900;">>></span><span style="color:#657B83;"> </span><span style="color:#2AA198;">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-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">python</span><span style="color:#839496;"> </span><span style="color:#2AA198;">simple_s3.py</span><span style="color:#839496;"> </span><span style="color:#2AA198;">XXXX</span><span style="color:#839496;"> </span><span style="color:#2AA198;">upload</span><span style="color:#839496;"> </span><span style="color:#2AA198;">tmp.txt</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">python</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">simple_s3.py</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">XXXX</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">upload</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">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 solarized-dark vp-code-dark"><code><span class="line"><span style="color:#93A1A1;font-weight:bold;">def</span><span style="color:#839496;"> </span><span style="color:#268BD2;">upload_file</span><span style="color:#839496;">(bucket_name, filename, key</span><span style="color:#859900;">=</span><span style="color:#B58900;">None</span><span style="color:#839496;">):</span></span>
|
||
<span class="line"><span style="color:#839496;"> bucket </span><span style="color:#859900;">=</span><span style="color:#839496;"> s3.Bucket(bucket_name)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#859900;">if</span><span style="color:#839496;"> key </span><span style="color:#859900;">is</span><span style="color:#839496;"> </span><span style="color:#B58900;">None</span><span style="color:#839496;">:</span></span>
|
||
<span class="line"><span style="color:#839496;"> key </span><span style="color:#859900;">=</span><span style="color:#839496;"> os.path.basename(filename)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#839496;"> bucket.upload_file(filename, key)</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#586E75;font-weight:bold;">def</span><span style="color:#657B83;"> </span><span style="color:#268BD2;">upload_file</span><span style="color:#657B83;">(bucket_name, filename, key</span><span style="color:#859900;">=</span><span style="color:#B58900;">None</span><span style="color:#657B83;">):</span></span>
|
||
<span class="line"><span style="color:#657B83;"> bucket </span><span style="color:#859900;">=</span><span style="color:#657B83;"> s3.Bucket(bucket_name)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#859900;">if</span><span style="color:#657B83;"> key </span><span style="color:#859900;">is</span><span style="color:#657B83;"> </span><span style="color:#B58900;">None</span><span style="color:#657B83;">:</span></span>
|
||
<span class="line"><span style="color:#657B83;"> key </span><span style="color:#859900;">=</span><span style="color:#657B83;"> os.path.basename(filename)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#657B83;"> 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-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">python</span><span style="color:#839496;"> </span><span style="color:#2AA198;">simple_s3.py</span><span style="color:#839496;"> </span><span style="color:#2AA198;">XXXX</span><span style="color:#839496;"> </span><span style="color:#2AA198;">upload</span><span style="color:#839496;"> </span><span style="color:#2AA198;">tmp.txt</span><span style="color:#839496;"> </span><span style="color:#CB4B16;">--key</span><span style="color:#839496;"> </span><span style="color:#2AA198;">a/b/tmp.txt</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">python</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">simple_s3.py</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">XXXX</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">upload</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">tmp.txt</span><span style="color:#657B83;"> </span><span style="color:#CB4B16;">--key</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">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>"/" (スラッシュ)</strong> によって区切られていた場合,<strong>ツリー状の階層構造</strong>によってファイルを管理することができる.</p><p>オブジェクトストレージには本来ディレクトリという概念はない. 上で紹介した "/" による階層づけはあくまでユーザー体験向上の目的のお化粧的な機能である.</p><p>次に,バケットからファイルのダウンロードを実行してみよう. <code>simple_s3.py</code> を使って,以下のコマンドを実行すればよい. <code>XXXX</code> のところは,自分自身のバケットの名前で置き換えること.</p><div class="language-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">python</span><span style="color:#839496;"> </span><span style="color:#2AA198;">simple_s3.py</span><span style="color:#839496;"> </span><span style="color:#2AA198;">XXXX</span><span style="color:#839496;"> </span><span style="color:#2AA198;">download</span><span style="color:#839496;"> </span><span style="color:#2AA198;">tmp.txt</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">python</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">simple_s3.py</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">XXXX</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">download</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">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 solarized-dark vp-code-dark"><code><span class="line"><span style="color:#93A1A1;font-weight:bold;">def</span><span style="color:#839496;"> </span><span style="color:#268BD2;">download_file</span><span style="color:#839496;">(bucket_name, key, filename</span><span style="color:#859900;">=</span><span style="color:#B58900;">None</span><span style="color:#839496;">):</span></span>
|
||
<span class="line"><span style="color:#839496;"> bucket </span><span style="color:#859900;">=</span><span style="color:#839496;"> s3.Bucket(bucket_name)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#839496;"> </span><span style="color:#859900;">if</span><span style="color:#839496;"> filename </span><span style="color:#859900;">is</span><span style="color:#839496;"> </span><span style="color:#B58900;">None</span><span style="color:#839496;">:</span></span>
|
||
<span class="line"><span style="color:#839496;"> filename </span><span style="color:#859900;">=</span><span style="color:#839496;"> os.path.basename(key)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#839496;"> bucket.download_file(key, filename)</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#586E75;font-weight:bold;">def</span><span style="color:#657B83;"> </span><span style="color:#268BD2;">download_file</span><span style="color:#657B83;">(bucket_name, key, filename</span><span style="color:#859900;">=</span><span style="color:#B58900;">None</span><span style="color:#657B83;">):</span></span>
|
||
<span class="line"><span style="color:#657B83;"> bucket </span><span style="color:#859900;">=</span><span style="color:#657B83;"> s3.Bucket(bucket_name)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#657B83;"> </span><span style="color:#859900;">if</span><span style="color:#657B83;"> filename </span><span style="color:#859900;">is</span><span style="color:#657B83;"> </span><span style="color:#B58900;">None</span><span style="color:#657B83;">:</span></span>
|
||
<span class="line"><span style="color:#657B83;"> filename </span><span style="color:#859900;">=</span><span style="color:#657B83;"> os.path.basename(key)</span></span>
|
||
<span class="line"></span>
|
||
<span class="line"><span style="color:#657B83;"> 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 "スタックの削除""></a></h3><p>以上のハンズオンで, S3 の一番基本的な使い方を紹介した. ここまでのハンズオンが理解できたら,忘れずにスタックを削除しよう. これまでのハンズオンと同様,スタックを削除するには,次のコマンドを実行すればよい.</p><div class="language-shell vp-adaptive-theme line-numbers-mode"><button title="Copy Code" class="copy"></button><span class="lang">shell</span><pre class="shiki solarized-dark vp-code-dark"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#839496;"> </span><span style="color:#2AA198;">cdk</span><span style="color:#839496;"> </span><span style="color:#2AA198;">destroy</span></span></code></pre><pre class="shiki solarized-light vp-code-light"><code><span class="line"><span style="color:#268BD2;">$</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">cdk</span><span style="color:#657B83;"> </span><span style="color:#2AA198;">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-6c4a7022 data-v-b5edbda4><!--[--><!--[--><!--[--><!--[--><!----><!--]--><!--]--><!--]--><!--]--><div class="edit-info" data-v-b5edbda4><div class="edit-link" data-v-b5edbda4><a class="VPLink link edit-link-button" href="https://github.com/andatoshiki/toshiki-notebook/edit/master/docs/development/aws/handson-serverless.md" target="_blank" rel="noreferrer" data-v-b5edbda4 data-v-075865b7><!--[--><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" class="edit-link-icon" aria-label="edit icon" data-v-b5edbda4><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-b5edbda4><p class="VPLastUpdated" data-v-b5edbda4 data-v-00fbdbd8>Last updated: <time datetime="2023-06-11T18:14:34.000Z" data-v-00fbdbd8></time></p></div></div><div class="prev-next" data-v-b5edbda4><div class="pager" data-v-b5edbda4><a class="pager-link prev" href="/development/aws/serverless" data-v-b5edbda4><span class="desc" data-v-b5edbda4>Previous page</span><span class="title" data-v-b5edbda4>Serverless architecture</span></a></div><div class="has-prev pager" data-v-b5edbda4><a class="pager-link next" href="/development/aws/handson-bashoutter" data-v-b5edbda4><span class="desc" data-v-b5edbda4>Next page</span><span class="title" data-v-b5edbda4>Hands-on 6: Bashoutter</span></a></div></div></footer><!--[--><!--[--><!--[--><div id="comment-container"></div><!--]--><!--]--><!--]--></div></div></div><!--[--><!--]--></div></div><footer class="VPFooter has-sidebar" data-v-83f63849 data-v-02da8605><div class="container" data-v-02da8605><p class="message" data-v-02da8605>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-02da8605>Copyright © 2023-2023 <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>__VP_HASH_MAP__ = JSON.parse("{\"academic_literature_index.md\":\"7de6baf3\",\"academic_chemistry_problems_03-02-2.md\":\"88fe1e80\",\"academic_chemistry_problems_03-02-3.md\":\"c40ff52c\",\"academic_literature_writing_methods-of-development.md\":\"ecdd05df\",\"academic_physics_index.md\":\"a0840729\",\"academic_physics_ipho-formulas-jpn_5.md\":\"b1ee40d7\",\"academic_physics_ipho-formulas-jpn_13.md\":\"bb0ff494\",\"academic_physics_ipho-formulas-jpn_2.md\":\"fa4c1b3e\",\"academic_physics_ipho-formulas-jpn_6.md\":\"b718f7cf\",\"academic_physics_ipho-formulas-jpn_10.md\":\"372e0532\",\"academic_chemistry_notes_12-5.md\":\"120853e2\",\"academic_physics_ipho-formulas-jpn_3.md\":\"d8114217\",\"academic_physics_ipho-formulas-jpn_8.md\":\"fd0c72fb\",\"academic_physics_ipho-formulas-jpn_4.md\":\"585981a4\",\"academic_physics_ipho-formulas-jpn_7.md\":\"a28ba1ce\",\"academic_chemistry_problems_02-20.md\":\"0a08e7fe\",\"academic_chemistry_index.md\":\"bcd40f8e\",\"development_aws_handson-qabot.md\":\"31aa6987\",\"development_aws_scientific-computing.md\":\"edc1ca8e\",\"development_aws_serverless.md\":\"b3a6787b\",\"development_aws_webserver.md\":\"ec4090fe\",\"development_file-naming-convention.md\":\"365eaa27\",\"getting-started.md\":\"cb569334\",\"index.md\":\"e1d327be\",\"javascript_notes_1_1-1.md\":\"1a1553c1\",\"javascript_notes_1_1-2.md\":\"520d2612\",\"jp_index.md\":\"c8456ef8\",\"academic_physics_ipho-formulas-jpn_1.md\":\"2a363f4f\",\"roadmap.md\":\"bd9ae73c\",\"save_reading_index.md\":\"203c05d5\",\"save_reading_outliers_1.md\":\"689a93ab\",\"save_reading_outliers_4.md\":\"e1125fc5\",\"development_aws_handson-ec2.md\":\"b5c1f295\",\"academic_physics_ipho-formulas-jpn_12.md\":\"72fcba20\",\"academic_physics_ipho-formulas-jpn_11.md\":\"15b2efd6\",\"academic_physics_ipho-formulas-jpn_9.md\":\"e617fa96\",\"academic_vocabulary_2023_02_2023-02-27.md\":\"07620cdb\",\"academic_vocabulary_index.md\":\"7151e4ef\",\"application_markdown-it-katex_how-to-use.md\":\"ac1ba08d\",\"application_markdown-it-katex_tips.md\":\"780a3572\",\"application_vitepress-plugin-shiki-twoslash_api_annotations.md\":\"55a88eef\",\"application_vitepress-plugin-shiki-twoslash_api_cutting.md\":\"a79988ba\",\"application_vitepress-plugin-shiki-twoslash_api_emit.md\":\"56527051\",\"application_vitepress-plugin-shiki-twoslash_api_errors.md\":\"63061c8b\",\"application_vitepress-plugin-shiki-twoslash_api_includes.md\":\"886726ac\",\"application_vitepress-plugin-shiki-twoslash_api_logging.md\":\"6a12cf42\",\"application_vitepress-plugin-shiki-twoslash_api_multi-file.md\":\"a4da6831\",\"application_vitepress-plugin-shiki-twoslash_api_queries.md\":\"7ea3a654\",\"application_vitepress-plugin-shiki-twoslash_api_types.md\":\"945e165a\",\"application_vitepress-plugin-shiki-twoslash_config_flags.md\":\"3d903c32\",\"application_vitepress-plugin-shiki-twoslash_config_reference.md\":\"ba174ed3\",\"application_vitepress-plugin-shiki-twoslash_guide_custom-theme.md\":\"fe881318\",\"application_vitepress-plugin-shiki-twoslash_guide_markdown-extensions.md\":\"bfab77c2\",\"application_vitepress-plugin-shiki-twoslash_index.md\":\"1a25976d\",\"development_aws_acknowledgement.md\":\"f478410c\",\"development_aws_appendix.md\":\"881e911c\",\"development_aws_assignments.md\":\"fefdbf16\",\"development_aws_closing.md\":\"a1032775\",\"development_aws_aws-batch.md\":\"4c4eb56e\",\"development_aws_aws-get-started.md\":\"59e85025\",\"save_reading_outliers_3.md\":\"3fc0e969\",\"development_aws_index.md\":\"2b7c99bc\",\"save_reading_outliers_2.md\":\"80ca398b\",\"development_aws_handson-bashoutter.md\":\"4536587b\",\"development_aws_author.md\":\"2ad76354\",\"development_aws_docker-system.md\":\"aa852e4a\",\"development_rclone-for-r2.md\":\"a2544b72\",\"development_aws_main.md\":\"37a00105\",\"development_aws_handson-jupyter.md\":\"6d80eb7c\",\"development_aws_license.md\":\"951cee54\",\"development_aws_handson-serverless.md\":\"d45efc0b\",\"academic_chemistry_problems_03-02-1.md\":\"29d530cc\",\"development_aws_cloud.md\":\"7a2ee032\",\"application_markdown-it-katex_support-table.md\":\"2866f602\",\"application_markdown-it-katex_support-function.md\":\"41eb822d\"}")
|
||
__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/\"},{\"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\":\"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\":\"コードで学ぶ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/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-2023 <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> |