20210509のAWSに関する記事は11件です。

マインドマップでAWSのデータ分析サービスを勉強【データ処理編】第�2回 − EMR

AWSのデータ分析系のサービスを体系的に勉強シリーズです。 一般的なデータ分析流れに含まれる、データ収集、データ保存、データ処理、データ分析、データ可視化、といったステップにそれぞれが利用するサービスを学び、マインドマップに整理しました。 今回はデータ処理編のEMRです。 ※ こちらの記事は、AWSのホワイトペーパー、クラウドサービス活用資料集とUdemyにあるAWS Certified Data Analytics Specialty 2021 - Hands onコースを参照しております。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】通信プロトコルについて

プログラミング勉強日記 2021年5月9日 通信のルール  インターネット通信のときにメールやWebアクセスなど目的によって通信方法が変わる。  例えば、メールの設定をするときにはPOPとSMTPにIPアドレスのような設定をすることがある。(送信メールサーバーがSMTPサーバーで、受信メールサーバーがPOP・IMAPサーバー) SMTPはSimple Mail Transfer Protocolでメールの送信プロトコル。POPはPost Office Protocolでメール受信のプロトコル。このようにメールの送受信するときにはWebとは違うプロトコルを使っている。このプロトコルでの送受信をするためのサーバーのIPアドレスをメーラーに設定している。  HTTP(Hyper Text Transfer Protocol)はHTML(Hyper Text Markup Language)で書かれた文書などの情報をやりとりするときに使われるプロトコル。 OSI参照モデル  OSI参照モデルは通信プロトコルを性質や送信対象に応じて7つの層に分けている規約。 層 名称 規格(プロトコル) 概要 利用例 7層 アプリケーション層 HTTP,FTP,DNS,SMTP,POPなど 個々のアプリケーション www,メール 6層 プレゼンテーション層 SMTP,FTP,Telnetなど データの表現形式 HTML 5層 セッション層 TLS,NetBIOSなど 通信手段 HTTPS 4層 トランスポート層 TCP,UDP,NetWare/IPなど エンド間の通信制御 TCP,UDP 3層 ネットワーク層 IP,ARP,RARP,ICMPなど データを送る相手を決め最適な経路で送信 IP 2層 データリンク層 PPP,Ethernetなど 隣接する機器同士の通信を実現 Ethernet 1層 物理層 RS-232,UTP,無線 物理的な接続、電気信号 UTPケーブル,光ファイバーケーブル アプリケーション層  Webアプリケーションなどの通信サービスの通信方法を規定する。アプリケーション層はOutlookやChromeのようなアプリケーションを実行するときの通信を実施するもの。Webアプリケーションの通信サービスが実現できるように固有の規定を定義している。この中でアプリケーションごとにプロトコルが細分化されている。(メールソフトウェア用プロトコルはPOP/SMTP, Webブラウザ用プロトコルはHTTP/HTTPSなど) プレゼンテーション層  文字を送受信するときに文字コードや暗号などを規定する。要するに、文字の送り方を決めている。送信側と受信側で形式が異なっても世界中でWebサイトが表示されるのはプレゼンテーション層があるため。 セッション層  セッション(アプリケーション間での一連の通信処理の継続)の仕方を規定する。 トランスポート層  最初にWebサイトにアクセスの通信を許可する(セッションを開始するときの信頼確立)や、到着順序や確認などを実施する。 ネットワーク層  IPアドレスを利用したルーティング方法を規定する。 データリング層  MACアドレスによるノード間の通信方法を規定する。 物理層  ビット単位によるコンピュータ間の物理的なデータのやりとりを規定する。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amazon Web Services で IPv6 を使う

AWS で IPv6 がどの程度使えるかと、使う方法をざっくりとまとめました。(手順の詳細は割愛します。) 参考) AWS における IPv6 対応状況 2020 IPv4 の現状 2011 年 2 月、IANA による最後の IPv4 アドレスブロックの割り当てが完了したという大きなニュースからはや 10 年。アドレスが枯渇すると言われて久しい IPv4 ですが、今はどうなっているのでしょうか。「そんなのあったねえ」なんて、一過性のブームみたいに捉えられていないでしょうか。 現在の IPv4 アドレスプールの残りは IPv4 Address Report で確認することができます。さすがにいよいよ限界な気がします。自粛要請が必要です。 IPv6 化のメリット・デメリット 大量の IP アドレスが利用可能(?) IPv4 の場合、ひとつの VPC に割り振れるアドレスは 16bit (65,536 個) まで。サブネットを分ける場合は各サブネット作成時にこれを振り分ける必要があり、あとから変更することはできません。一方 IPv6 は各サブネットで常に 64bit (1844 京) が使えるので、実質無限です。とは言え、IPv4/IPv6 のデュアルスタックなので、結局 IPv4 アドレスの数で作成できるインスタンス数は頭打ちです。惜しい!(誰がそんなに使うんだって話しですが) IPv4 グローバルアドレス、Elastic IP が不要(?) AWS から固定の IPv6 プレフィックスが割り当てられ、個々のホストも固定の IPv6 アドレスとなります。有限のグローバル IPv4 アドレスを取り合う必要がありません。とはいえ直接公開することも少ないでしょうし、IPv4 でのアクセスも必要な場合は必要になります。管理用にグローバルアクセスが必要なだけであれば、IPv4 グローバルアドレスを消費せず節約にささやかながら貢献しましょう! NAT が不要(?) IPv6 ではすべてのホストがグローバルアドレスを持ち、アドレス変換が不要となります。とは言え外部からの通信には IPv4 同様、Internet Gateway が必要になります。Internet Gateway への経路がないプライベートサブネットからインターネットへ IPv6 で通信するには、NAT の代わりに Egress Only Internet Gateway を設置します。これは NAT と違い無料なので、プライベートサブネットからの通信が IPv6 だけで良いのであれば、NAT ゲートウェイ/インスタンスのコストが不要になります。外部からプライベートサブネット内へのインバウンド通信は NAT 同様に防がれます。 注意 現状 AWS API の IPv6 対応は進んでいないため、プライベートサブネット内から AWS リソースにアクセスするにはやはり NAT または VPC エンドポイントが必要になります。 Lambda も IPv6 対応されていないため、VPC に収容した Lambda からインターネットや AWS リソースにアクセスするにはやはり NAT や VPC エンドポイントが必要になります。 デメリット: 管理コストが増える IPv6 化しても IPv4 を無効化することはできずデュアルスタック運用になるため、管理すべき項目が単純に増えます。セキュリティ面も意識する必要があります。IPv6 に起因するトラブルが発生する可能性もあるでしょう。完全に IPv6 だけにできれば良いのですが...まだまだ先のことです。 デメリット: アドレス指定が面倒 アドレスが長くて覚えづらいですか?僕は IPv4 でも覚えていないので問題ないです。 設定方法 Amazon VPC/EC2 参考) Amazon VPC での IPv6 の使用開始 VPC に対して IPv6 を有効にする。 56bit プレフィックスが自動的に割り当てられる(選択は不可)。 各サブネットに対して残りの 8bit を振り分ける。 プライベートサブネットからインターネット通信をする場合、NAT の代わりに Egress Only Internet Gateway が必要(無料)。 IPv6 ではグローバルアドレスのみなのでアドレス変換なく外部と通信ができるが、外部から内部への向きの通信はできないことでセキュリティを確保する。 ルートテーブル、セキュリティグループ、ネットワーク ACL に適宜 IPv6 の設定を追加する。 Amazon CloudFront 「Enable IPv6」設定を有効にする(デフォルト有効)。 カスタムドメイン運用時は AAAA レコードも CloudFront ディストリビューションに向けること。 Elastic Load Balancing インターネット向け ALB および NLB のみ対応。 VPC に対して IPv6 が有効であり、ALB を収容するサブネットに IPv6 サブネットを割り当て済みであること。 「IP アドレスタイプ」に「dualstack」を選択する。 カスタムドメイン運用時は AAAA レコードも ALB に向けること。 補足 ALB エンドポイントに「dualstack」がつくものとつかないものが存在しますが、どちらを使っても変わらないようです。 例) dualstack.xxxxxxxx.ap-northeast-1.elb.amazonaws.com Elastic Beanstalk からは ALB に IPv6 を設定できないようです。作成された ALB に直接設定すれば有効にすることはできますが、AAAA レコードを Alias 設定する場合、Beanstalk のエンドポイントへ向けることはできないので、生成された ALB のエンドポイントに直接向ける必要があります。 Amazon S3 デュアルスタックのエンドポイントを指定することで、IPv6 でのアクセスをおこなうことができます。ただし、VPC エンドポイントは IPv6 には対応していないため、VPC エンドポイントを経由することはできません。 参考) Amazon S3 デュアルスタックのエンドポイントを使用する 例えば AWS CLI でデュアルスタックのエンドポイントを使用するには、以下を設定します。AWS SDK での方法は各言語の SDK を参照してください。 aws configure set default.s3.use_dualstack_endpoint true これにより、~/.aws/config に以下のように設定されます。 [default] s3 = use_dualstack_endpoint = true その他 以下のサービスも IPv6 対応しています。 AWS IoT (これこそ IPv6 の出番ですね) AWS WAF Direct Connect Route 53 他に欲しいところとして、以下のサービスは未対応のようです。今後に期待しています。 Amazon API Gateway Amazon RDS AWS Elastic Beanstalk AWS Lambda VPC Endpoint さいごに こうやって見てみると、正直まだ制限も多く IPv6 対応しようというモチベーションにつながるものがないのも事実です。IPv6 界隈そんな感じでずっときてはいますが、インフラの IPv6 化は着実に進んできています。クラウドサービスの IPv6 対応は遅れているほうではないでしょうか。顧客要望がない状況でも、インターネットの未来を牽引していって欲しいものです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【SPA】Nuxt.js,TypeScript,AWS,graphQLで作るインスタクローンアプリ

目次 作品リンク 作成目的 使用技術 アプリの使い方 1.作品リンク amplifyにてホスティングしました。 https://master.d2qrnepigha0wa.amplifyapp.com/ 2.作成目的 学習のアウトプット ポートフォリオとしての使用 3.使用技術 フロントエンド HTML/CSS TypeScript Nuxt.js(SPAモード) Vuetify(UIフレームワーク) ESLint/Prettier(コード解析ツール) バックエンド・インフラ Amplify(インフラ構築) GraphQL(API呼び出し) AppSync(API管理) DynamoDB(データベース) S3(画像ストレージ) Cognito(ユーザー認証) GitHub(バージョン管理) インフラ構成図 ER図 4.アプリの使い方 機能名 説明 ユーザー機能 新規登録・メールアドレスによる確認・登録内容変更・アイコン登録・ログイン・ログアウト・ゲストユーザー 投稿機能 投稿、編集、削除、画像複数枚登録 コメント機能 投稿に対してコメント投稿 いいね機能 投稿をいいねできる ①ユーザー機能 登録・編集 ユーザー名・メールアドレス・パスワードでアカウントを作成します。 同時にアイコンの登録も可能です。 パスワードとメールアドレスはcognitoのユーザープールにて管理され、データベースに保存されません。 登録の際に入力いただいたメールアドレスに、確認コードを送信し、 確認が完了すると機能をお使いいただけます。 (ここで確認しなかった場合、ログインの際に確認機能を挟むようになっています。) 会員登録 ログイン ゲストユーザーでのログインも用意しました。 ゲストユーザー ログイン画面・アカウントの新規登録画面に、ゲストログインのボタンを配置し、気楽に使用できるようにしました。 ②.投稿機能 投稿の作成、削除は即時に反映されます。 画像は最低1枚は登録必須になります。 登録枚数の制限はありません。 ③.いいね機能 投稿に対し、いいねできます。自分がいいねしている場合は、いいねを外すことももちろん可能です。 ④.コメント機能 投稿詳細ダイアログから、投稿に対してコメントできます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【M1必見】Docker を使ってデータ解析環境を構築する

なぜDocker を使うのか  結論から言うと、PCが汚れるのを防ぐため。HOSTコンピューター(自分が普段使うコンピュータ)に様々なパッケージを入れると、手間がかかるし、アンインストールしてもキャッシュが残ったりして、ストレージが少なくなってしまう。Dockerのコンテナを使い仮想環境を構築して、その中に様々なパッケージをインストールすることで、HOSTコンピュータに負荷をかけることなく、データ解析、分析が可能になる。さらに、インストールしたパッケージ同士がエラーを起こした際に、対応しやすいという利点もある。それに加えて、Dockerfileを共有することで、同じ環境が他の人でもコマンド一つで構築できてしまうという利点もある。 Dockerfile を作成する Dockerfileを作成する方法はいくらでもあるが、個人的には、https://code.visualstudio.com/ を使うことをお勧めする dockerfile # ubuntuをベースに docker image を作成する FROM ubuntu:latest # メンテナンスなどによく使われるコマンドをインストールする(-yはパッケージをインストールする際に必要なおまじない) RUN apt-get update && apt-get install -y wget vim sudo # WORKDIR でインストールする場所を決める WORKDIR <Anacondaをインストールする場所、推奨は「/opt」> RUN wget https://repo.continuum.io/archive/Anaconda3-2020.11-Linux-x86_64.sh <- インストールしたいAnacondaのバージョン Anacondaのバージョンなどについては、 https://repo.anaconda.com/archive/ を参照するといい。ubuntuに対応しているのは、「Anaconda3-2019.10-Linux-x86_64.sh」のように、「Linux-x86」が入っているもの dockerfile # anacondaインストーラーを起動し、anaconda3をインストールする # -b : バッチファイル的に動かすときに使用する(必須) # -p path :anacodna3をどこに置くかを指定する(デフォルトでは、root/anacodna3となる。メンテがめんどいので、optの下においた) RUN sh Anaconda3-2020.11-Linux-x86_64.sh -p /opt/anaconda3 -b # ENVで環境変数を設定する。以下は"python"のためのパス ENV PATH /opt/anaconda3/bin:$PATH # "jypyter", "lab" :jupyterlabをデフォルトで起動させるコマンド。 # "--ip=0.0.0.0" :ローカルでjupyterlabを使うときに必要なコマンド # "--LabApp.token=''" :本来ならjupyterlabを起動させた際にパスワードを入れる必要があるがこう書くことでそれを防ぐ CMD ["jupyter", "lab", "--ip=0.0.0.0", "--allow-root", "--LabApp.token=''"] Dockerfileを用いて、"docker image"を作成する terminal username@MacBook-Pro ~ % cd <Dockerfileを保存した場所> # Dockerfileがあるかどうかを確認する username@MacBook-Pro docker_file % ls >>> Dockerfile # "docker build"を使って構築する username@MacBook-Pro docker_file % docker build --platform linux/amd64 上記と同じコマンドを入力すれば、docker imageを作成できる。 【重要】M1Macを使用している方は、必ず「--platform linux/amd64」を付けて入力する 付けないとエラーになる ターミナルでDockerfileを起動させる terminal # "docker iamges" を使い、起動したい "docker image" があるかどうかを確認する username@MacBook-Pro ~ % docker iamges >>> REPOSITORY TAG IMAGE ID CREATED SIZE <none> <none> dge767nb2v62h 2 days ago 3.66GB # "docker run" を使い "docker image" を起動させる # "-p 8888:8888" はポートを設定するためのオプションなので必須。もし以前に8888を使用したことがあるのであれば、任意のもの(-p 1234:8888)を設定する。 username@MacBook-Pro ~ % docker run -p 8888:8888 dge767nb2v62h 起動させると勝手にJupyterLabが起動するので、Googleで「localhost:8888」と検索するとJupyterlabに入ることができる。入れることを確認できたら、完了。 さらにライブラリを追加したいとき 先ほど作成したDockerfileに以下のコマンドと追加したいライブラリを入力すればいい。追記する場所は、CMDの上あたりでいい。 RUN pip install --upgrade pip RUN pip install <ライブラリの名前> 【補足】AWSでdockerを使用する ここのセクションではAWSにdockerをインストールして、自分のPCにマウントさせることで、自分のPCのメモリなどを使わずデータ分析を行う方法を紹介する。あらかじめAWSアカウント作成後、AWSインスタンスを作成しておくこと! 詳しくは、こちら( https://aws.amazon.com/jp/register-flow/)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

本当にざっくり理解AWS ネットワーク(概要編)

概要 AWS初心者、インフラを触った人がない人向けにざっくりとAWSで使うネットワークサービスの概要を伝えられればと思います。 本当にざっくりですし、詳しい概要はAWSが出しているAWS Black Beltを見ていただいた方が確かです。またこの資料を読むよりもAWSのハンズオン等に参加した方が理解が進むと思います。 参考資料: https://www.slideshare.net/AmazonWebServicesJapan/20201021-aws-black-belt-online-seminar-amazon-vpc この記事では以下の分類で説明させていただきます。AWSのソリューションアーキテクト-アソシエイトレベルだと、必須ではないが利用頻度が高いネットワークサービスまで抑えておけば大丈夫です。ちなみに今回は、必須ではないが利用頻度が高いネットワークサービスまで説明します。 AWS上でWebサービスを動かす上で必要なネットワークサービス VPC サブネット インターネットゲートウェイ 仮想ルータ ルートテーブル 必須ではないが利用頻度高いネットワークサービス VPCエンドポイント NATゲートウェイ ネットワークの構成上使う場合があるネットワークサービス VPC Peering カスタマゲートウェイ VPNコネクション バーチャルプライベートゲートウェイ Direct Connect AWS Transit Gateway AWS PrivateLink etc.. ネットワーク用語 AWSネットワークサービスを話す上で基本となる用語を説明します。 IPアドレス PCやサーバなど、TCP/IPで通信する機器を識別するためのアドレスのこと。 現実世界で郵便物を配達する際に住所が必要なのと同じように、ネットワークの世界でもデータを特定の機器に届けるためにIPアドレスが必要になります。 そしてIPアドレスには主に2種類があります。 パブリックIPアドレス(グローバルIPアドレスとも言う) インターネット接続に用いるIPアドレス プライベートIPアドレス インターネットには接続せず自分たちのネットワークで用いるIPアドレス サーバ、ネットワーク機器に割り当てる CIDR表記 CIDRは「サイダー」と呼びます。 IPアドレス+サブネットマスク(1つの数字)で書く書き方。AWSではネットワークの表記はCIDR表記になっています。 192.168.XXX.XXX/24 という形で記載します。 CIDR表記以外にサブネットマスク表記もあり、その場合192.168.1.0/255.255.255.0 という形で記載します。 ちなみにCIDRは総称は「Classless InterDomain Routing」で、アドレスクラスの概念を気にしないで自由にIPアドレスの割り当てを行える仕組みのことを指します。 従来は「クラスフル方式」と呼ばれる5つのクラスがあり、使用できるIPアドレスの数も決まっていました。 サブネットマスク IPアドレスがどこからどこまで使えるかを示す情報のことです。 例えば、 172.30.123.45/24 というCIDR表記のネットワークアドレス帯があるとすると以下のような計算になります。 IPアドレスを2進数に変換する /24 をサブネットマスク表記にし、2進数に変換する IPアドレスとサブネットマスクの論理和を求める まず /24 はサブネットマスクだと「255.255.255.0」になります。それを2進数に変換。ちなみに 1 がネットワーク部、 0 がホスト部になります。 ネットワーク部はIPアドレスが所属しているネットワークを決めます。ホスト部はIPアドレスがどれだけ使えるかを決めます。 11111111 11111111 11111111 00000000 次にIPアドレス「172.30.123.45」を2進数に変換します。 10101100 00011110 01111011 00101101 最後に2つの2進数の論理和を求めます。 IPアドレス: 10101100 00011110 01111011 00101101 サブネットマスク: 11111111 11111111 11111111 00000000 論理和: 10101100 00011110 01111011 00000000 論理和「10101100 00011110 01111011 00000000」は2進数にすると、 172.30.123.0 になり、これがネットワークアドレス(開始IP)になります。サブネットマスクのホスト部を全て1にすると 「10101100 00011110 01111011 11111111」 となり、これがブロードキャストアドレス(終了IP) 172.30.123.255 になります。 ネットワークアドレスとブロードキャストアドレスを抜かしたアドレスが、ホストアドレスとして使え、それが 「172.30.123.1〜172.30.123.254」の間のIPアドレスです。 必須ネットワークサービス VPC 論理的なネットワーク空間を作ることができるサービスです。 例えば、172.30.123.45/16 のネットワークアドレス帯が欲しければ、VPCで設定します。 AWSの推奨はRFC1918に則ったものを推奨しています。 参考資料: https://www.nic.ad.jp/ja/translation/rfc/1918.html サブネット VPC内部のネットワーク空間です。サブネット化することによって、ネットワーク空間を区切ることができて、余計なトラフィックがルーターに流れることがないので、ネットワークの効率が良くなります。 AWSでは、余計なトラフィックを流したくない場合は複数のサブネットを作ります。 ここは設計編でお話しします。 ちなみにサブネットはどこで作るかを設定する必要があり、AZ(Availability Zone)と紐づいています。 インターネットゲートウェイ インターネットからのアクセスを許可するために必要なネットワークサービスです。 仮想ルータ AWS上で意識することはありませんが、存在します。 ルートテーブル サブネットに設定するルーティングを定義するネットワークサービスです。 ルーティングテーブルをちゃんと設定しないとインターネットからのアクセスはできません。 まとめ 各AWSのネットワークサービスの関係性は以下の図の通りです。 今回紹介したサービス以外にRegionという概念がありますが、これは地域を示すものです。 東京であったり、大阪であったりが、Regionになります。Availability Zoneは例えば、Regionが東京の場合、東京の中でデータセンター(サーバが置いてある場所)が異なるということです。 必須ではないが利用頻度高いネットワークサービス NATゲートウェイ ここは、AWSの資料に勝る内容はないです。。 インターネットからのアクセスがないサブネットでも、インターネットに対してアクセスを行いたい場合にNATゲートウェイを使います。 引用: https://www.slideshare.net/AmazonWebServicesJapan/20201021-aws-black-belt-online-seminar-amazon-vpc#83 VPCエンドポイント パブリックIPアドレスを持つAWSサービスに対して、VPC内部から直接アクセスするための出口のことです。例えば、S3などにアクセスする場合、VPCエンドポイントを設定するとプライベートIPアドレスでもアクセスできるようになります。 VPCエンドポイントなし VPCエンドポイントあり VPCエンドポイントの種類 ちなみにVPCエンドポイントには2種類あります。 Gateway型とInterface型です。Gateway型はVPCに紐づき、Interface型はENIに紐づきます。アクセス制御の仕方や利用料金、冗長性は以下のAWS Black Beltの通り違いがあります。 引用: https://www.slideshare.net/AmazonWebServicesJapan/20201021-aws-black-belt-online-seminar-amazon-vpc#80 アクセス制御の方法 以上でAWSのネットワークサービスの説明が終わりですが、まだ重要なことを説明してません。それはアクセスの制御の仕方です。 アクセスを制御しなければ、インターネットからのアクセスを許可できませんし、アクセス許可をしすぎると攻撃される場合もあります。AWSでアクセス制御する場合は、セキュリティグループで制御するか、ネットワークACLで制御するかの2パターンがあります。 引用: https://www.slideshare.net/AmazonWebServicesJapan/20201021-aws-black-belt-online-seminar-amazon-vpc#47 私が関わっているプロジェクトでは、ネットワークACLではなく、セキュリティグループでアクセス制御をする場合が多いです。 ネットワークACLはサブネット内の全てに適用されてしまうので、コンピュートサービス(例: EC2)やマネージドサービス(例: Elasticache)で細かいアクセス制御がしにくくなってしまいます。 そのためセキュリティグループでアクセス制御をすることが多いです。ちなみに上記資料ではセキュリティグループは「サーバレベルで効果」と書いてますが、正しくはENIレベルでのアクセス制御を行います。 そのため、Interface型のVPCエンドポイントでセキュリティグループを設定したりします。 終わりに AWSのネットワーク設計をするために必要なネットワークサービスの概要であったり、ネットワークの知識を説明してきました。 次は具体的にどのようにサブネットを切るのか、どのようなアドレス帯がいいのかを経験をもとにお話しさせていただければと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

おうちにLambdaが欲しい!

はじめて投稿します、はるかなぎと申します。最近になり本格的にAWSを触り始めたいわばにわか勢です。 AWS Lambdaってなあに? AWS Lambdaは、サーバレス型と呼ばれるサービスのひとつで(利用者が)サーバを用意せずに、プログラムを実行できるサービスです。Faas(Function as a Service)と呼ばれる種類のサービスと説明されることもあります。 詳しい内容は、AWS公式の紹介ページを見た方が早いと思います。 AWS Lambda(イベント発生時にコードを実行)| AWS ところで、ローカルで動くの? この手のものを見ると、自宅に環境が欲しくなりますね。調べたところ、AWS SAM CLIというローカルでテストを行うツールがあるようです。 お試し用環境を用意します 早速遊んでみようと、以下のお試し用環境を用意しました。 OS:Amazon Linux 2(KVM用イメージ) ここに、SAM CLIとDockerをインストールしておきます。その他必要なツール(Git等)も一緒にインストールしておきます。(インストール方法は割愛します) 早速ためしてみる SAM CLIで作成したプロジェクトは以下のコマンドでローカル実行することが可能です。実行には、Dockerがインストールされている必要があります。(プロジェクトの作成については割愛します) $ sam local invoke Invoking app.lambda_handler (python3.7) Image was not found. Building image...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................... Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0. Mounting /home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated inside runtime container START RequestId: ac411f9d-c404-4ebf-bea9-e9ff1c6aa739 Version: $LATEST END RequestId: ac411f9d-c404-4ebf-bea9-e9ff1c6aa739 REPORT RequestId: ac411f9d-c404-4ebf-bea9-e9ff1c6aa739 Init Duration: 0.18 ms Duration: 93.27 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 128 MB {"statusCode": 200, "body": "{\"message\": \"hello world\"}"} sam local invokeで実行すると、上記の通り作成したLambda関数が実行されます。まぁここまでは普通の話です。SAM CLIでの実行にDockerが必要と書かれていたので、どのようなコンテナが作られるのか調べようと、意気揚々とコンテナ一覧を見てやろうとしたところ・・・ $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES あれ?何もないぞ?? 試しにイメージ一覧を出してみると、それらしきイメージが存在します。 $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE amazon/aws-sam-cli-emulation-image-python3.7 rapid-1.22.0 39513e8ac96d 3 minutes ago 908MB amazon/aws-sam-cli-emulation-image-python3.7 latest c8f4d7381293 About an hour ago 892MB まさかと思い、sam local invokeを叩いた直後にdocker psを連発してみたところ・・・ $ docker ps --no-trunc=true CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 0ab3d3c601864b1b539dddd7ac27c0972b09ceef137ed65c1acf9053e1884cba amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 "/var/rapid/aws-lambda-rie --log-level error" 3 seconds ago Up Less than a second 127.0.0.1:7706->8080/tcp busy_wiles お、出た出た。どうやら、SAM CLIで実行すると、Lambdaの実行環境を含んだDockerコンテナが作成され、実行後に削除するという動きをするようです。 イメージを調べてみよう 上記の手順で表示されたイメージは、Docker Hubにあるようです。 amazon/aws-sam-cli-build-image-python3.7 とりあえず作成されているイメージを消してから、dockerコマンドでpullしてみます。 $ docker pull amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 Error response from daemon: manifest for amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 not found: manifest unknown: manifest unknown ん?イメージが存在しない?試しにタグを指定せずにpullします。 $ docker pull amazon/aws-sam-cli-emulation-image-python3.7 Using default tag: latest latest: Pulling from amazon/aws-sam-cli-emulation-image-python3.7 df5bcad6d15c: Pull complete 1c6619c430f8: Pull complete 6577ccaf68c7: Pull complete 649bca99560c: Pull complete Digest: sha256:5358339925e231e94c2c4e0d917af54cadb312625a30df28cda271c5b844d9c9 Status: Downloaded newer image for amazon/aws-sam-cli-emulation-image-python3.7:latest docker.io/amazon/aws-sam-cli-emulation-image-python3.7:latest 無事にpullできました。 先ほどイメージを表示したときにもlatestのものが表示されていたので、どうやらSAM CLIでの実行時にlatestのイメージから作成しているようです。 ということは、イメージの差分を見れば、どのようなイメージかが分かります。もう一度SAM CLIで実行し、イメージを作成、historyを比較してみましょう。 まずはlatest $ docker history amazon/aws-sam-cli-emulation-image-python3.7:latest --no-trunc=true IMAGE CREATED CREATED BY SIZE COMMENT sha256:c8f4d7381293badf23098d75b891c50a6682a3146ed5c90a889f4685f0f90017 2 hours ago CMD [ "/bin/bash" ] 0B <missing> 2 hours ago ENV LAMBDA_RUNTIME_DIR=/var/runtime 0B <missing> 2 hours ago ENV LAMBDA_TASK_ROOT=/var/task 0B <missing> 2 hours ago ENV LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib 0B <missing> 2 hours ago ENV PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin 0B <missing> 2 hours ago ENV TZ=:/etc/localtime 0B <missing> 2 hours ago ENV LANG=en_US.UTF-8 0B <missing> 2 hours ago WORKDIR /var/task 0B <missing> 2 hours ago ADD file:649bca99560c52ca2195dc8410dbee9e1634faa448acfee4696f74db0651773f / 66.4MB <missing> 2 hours ago ADD file:6577ccaf68c7a9a42e7b1a8bbfa93959abc28b47888855eba289c032685c6770 / 173MB <missing> 2 hours ago ADD file:1c6619c430f8d56651115043ea1cd3e6d293434dc774f21cc087e86aebf6e1d4 / 424kB <missing> 2 hours ago ADD file:32665f54d46653b07d35bfa9cdd4baf9b1144d6824516a05218124afc01246f3 / 652MB <missing> 2 hours ago ARCHITECTURE amd64 0B 0B 次にrapid-1.22.0 ]$ docker history amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 --no-trunc=true IMAGE CREATED CREATED BY SIZE COMMENT sha256:b42538372e40f0627b62b40313690f2561f7bba02683c066e4221ea32dd2072b 5 minutes ago /bin/sh -c chmod +x /var/rapid/aws-lambda-rie 8.16MB sha256:cddd62fd80bd20c647cd6d8cc12ff1bfb822da1706e3e7eb9c44c705c559a55f 5 minutes ago /bin/sh -c #(nop) ADD dir:bf074fbf6e9076431dc41d00943644a0df7bd2853140615db6ae0130fd5c91f8 in /var/rapid 8.16MB sha256:c8f4d7381293badf23098d75b891c50a6682a3146ed5c90a889f4685f0f90017 2 hours ago CMD [ "/bin/bash" ] 0B <missing> 2 hours ago ENV LAMBDA_RUNTIME_DIR=/var/runtime 0B <missing> 2 hours ago ENV LAMBDA_TASK_ROOT=/var/task 0B <missing> 2 hours ago ENV LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib 0B <missing> 2 hours ago ENV PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin 0B <missing> 2 hours ago ENV TZ=:/etc/localtime 0B <missing> 2 hours ago ENV LANG=en_US.UTF-8 0B <missing> 2 hours ago WORKDIR /var/task 0B <missing> 2 hours ago ADD file:649bca99560c52ca2195dc8410dbee9e1634faa448acfee4696f74db0651773f / 66.4MB <missing> 2 hours ago ADD file:6577ccaf68c7a9a42e7b1a8bbfa93959abc28b47888855eba289c032685c6770 / 173MB <missing> 2 hours ago ADD file:1c6619c430f8d56651115043ea1cd3e6d293434dc774f21cc087e86aebf6e1d4 / 424kB <missing> 2 hours ago ADD file:32665f54d46653b07d35bfa9cdd4baf9b1144d6824516a05218124afc01246f3 / 652MB <missing> 2 hours ago ARCHITECTURE amd64 0B /var/rapid/配下にファイルを追加し、/var/rapid/aws-lambda-rieに実行権限を付与しているという違いが見つかりました。この/var/rapid/aws-lambda-rieの有無がこの2つのイメージの違いのようです。 aws-lambda-rieってなあに? ではこのaws-lambda-rieって何者なのか調べたところ、AWS Lambda Runtime Interface Emulatorと呼ばれるもので、名前の通りLambda実行環境のエミュレータのようです。 ここで、先ほどのコンテナ一覧の結果を見てみましょう。COMMANDの箇所を見ると「/var/rapid/aws-lambda-rie --log-level error」とあるので、まさにこいつをコンテナ作成時に実行しています。 コンテナの中身はなんだろな では、次にコンテナを調べていきます。 先ほどの情報だけだと足りないので、docker inspectコマンドで中身を見てみます。 しかし、実行時にコンテナが作成され、実行後に削除される関係上、まともにコマンドを叩いていては間に合わないので、簡単なスクリプトを作って取得します。なお、目的のコンテナの情報さえ取れれば良いということで複数コンテナが動いている状況はまったく考慮していませんのでご注意ください。 #!/bin/bash CONTAINER_ID=`docker ps -q` echo ${CONTAINER_ID} docker inspect ${CONTAINER_ID} コンテナが起動している間にこのスクリプトを実行すると以下のような情報が得られます。 [ { "Id": "85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829", "Created": "2021-04-26T13:20:45.676396302Z", "Path": "/var/rapid/aws-lambda-rie", "Args": [ "--log-level", "error" ], "State": { "Status": "removing", "Running": false, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": true, "Pid": 0, "ExitCode": 137, "Error": "", "StartedAt": "2021-04-26T13:20:47.643574462Z", "FinishedAt": "2021-04-26T13:20:49.361733871Z" }, "Image": "sha256:b42538372e40f0627b62b40313690f2561f7bba02683c066e4221ea32dd2072b", "ResolvConfPath": "/var/lib/docker/containers/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829/resolv.conf", "HostnamePath": "/var/lib/docker/containers/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829/hostname", "HostsPath": "/var/lib/docker/containers/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829/hosts", "LogPath": "/var/lib/docker/containers/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829/85faef4d31c713bf1b246f7d36d1347792d419a9eef797ae1b0a804b95c57829-json.log", "Name": "/elated_archimedes", "RestartCount": 0, "Driver": "overlay2", "Platform": "linux", "MountLabel": "", "ProcessLabel": "", "AppArmorProfile": "", "ExecIDs": null, "HostConfig": { "Binds": [ "/home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction:/var/task:ro,delegated" ], "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "default", "PortBindings": { "8080/tcp": [ { "HostIp": "127.0.0.1", "HostPort": "5018" } ] }, "RestartPolicy": { "Name": "", "MaximumRetryCount": 0 }, "AutoRemove": false, "VolumeDriver": "", "VolumesFrom": null, "CapAdd": null, "CapDrop": null, "Capabilities": null, "Dns": null, "DnsOptions": null, "DnsSearch": null, "ExtraHosts": null, "GroupAdd": null, "IpcMode": "shareable", "Cgroup": "", "Links": null, "OomScoreAdj": 0, "PidMode": "", "Privileged": false, "PublishAllPorts": false, "ReadonlyRootfs": false, "SecurityOpt": null, "UTSMode": "", "UsernsMode": "", "ShmSize": 67108864, "Runtime": "runc", "ConsoleSize": [ 0, 0 ], "Isolation": "", "CpuShares": 0, "Memory": 134217728, "NanoCpus": 0, "CgroupParent": "", "BlkioWeight": 0, "BlkioWeightDevice": null, "BlkioDeviceReadBps": null, "BlkioDeviceWriteBps": null, "BlkioDeviceReadIOps": null, "BlkioDeviceWriteIOps": null, "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpusetCpus": "", "CpusetMems": "", "Devices": null, "DeviceCgroupRules": null, "DeviceRequests": null, "KernelMemory": 0, "KernelMemoryTCP": 0, "MemoryReservation": 0, "MemorySwap": 268435456, "MemorySwappiness": null, "OomKillDisable": false, "PidsLimit": null, "Ulimits": [ { "Name": "nofile", "Hard": 4096, "Soft": 1024 } ], "CpuCount": 0, "CpuPercent": 0, "IOMaximumIOps": 0, "IOMaximumBandwidth": 0, "MaskedPaths": [ "/proc/asound", "/proc/acpi", "/proc/kcore", "/proc/keys", "/proc/latency_stats", "/proc/timer_list", "/proc/timer_stats", "/proc/sched_debug", "/proc/scsi", "/sys/firmware" ], "ReadonlyPaths": [ "/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger" ] }, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/af0a80a46c80ec4b4d59ce90e55969ec853bc7727d259898945277665b5dfac8-init/diff:/var/lib/docker/overlay2/3f3546128854b10663811112acc8423f84abcc1f47b3073172b55bdb3768a7af/diff:/var/lib/docker/overlay2/bcfc11b7e7c587d3a01e09c4c843a3525635ec782635bdc3e707cb56d0d5733b/diff:/var/lib/docker/overlay2/a10c8af58d6fa1f634045400e21b7f6dbbca281ba68a0ab9b5cf23ecaae7c9a7/diff:/var/lib/docker/overlay2/2cdd94e4f72dc4af42a1d5f1d25d8716ed0d7330261c5489ce847882c872d577/diff:/var/lib/docker/overlay2/a6630cafd3c07e2e8a198af012f75d3f035fc4e8ad2a69d5a2edc9d0da7c529c/diff:/var/lib/docker/overlay2/6f9c1a2e3d92bfb822c9f028fe7d98f964cd19a89b063f4082639dba4d1563ce/diff", "MergedDir": "/var/lib/docker/overlay2/af0a80a46c80ec4b4d59ce90e55969ec853bc7727d259898945277665b5dfac8/merged", "UpperDir": "/var/lib/docker/overlay2/af0a80a46c80ec4b4d59ce90e55969ec853bc7727d259898945277665b5dfac8/diff", "WorkDir": "/var/lib/docker/overlay2/af0a80a46c80ec4b4d59ce90e55969ec853bc7727d259898945277665b5dfac8/work" }, "Name": "overlay2" }, "Mounts": [ { "Type": "bind", "Source": "/home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction", "Destination": "/var/task", "Mode": "ro,delegated", "RW": false, "Propagation": "rprivate" } ], "Config": { "Hostname": "85faef4d31c7", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "ExposedPorts": { "8080/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "AWS_SAM_LOCAL=true", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE=128", "AWS_LAMBDA_FUNCTION_TIMEOUT=3", "AWS_LAMBDA_FUNCTION_HANDLER=app.lambda_handler", "AWS_LAMBDA_FUNCTION_NAME=HelloWorldFunction", "AWS_LAMBDA_FUNCTION_VERSION=$LATEST", "AWS_LAMBDA_LOG_GROUP_NAME=aws/lambda/HelloWorldFunction", "AWS_LAMBDA_LOG_STREAM_NAME=$LATEST", "AWS_REGION=us-east-1", "AWS_DEFAULT_REGION=us-east-1", "AWS_ACCESS_KEY_ID=defaultkey", "AWS_SECRET_ACCESS_KEY=defaultsecret", "AWS_ACCOUNT_ID=123456789012", "LANG=en_US.UTF-8", "TZ=:/etc/localtime", "PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", "LAMBDA_TASK_ROOT=/var/task", "LAMBDA_RUNTIME_DIR=/var/runtime" ], "Cmd": [], "Image": "amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0", "Volumes": { "/var/task": {} }, "WorkingDir": "/var/task", "Entrypoint": [ "/var/rapid/aws-lambda-rie", "--log-level", "error" ], "OnBuild": null, "Labels": {} }, "NetworkSettings": { "Bridge": "", "SandboxID": "1123e52e745924dc1fce7584d2985878104283b8ea348c9cae5c6466c4dfc591", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": {}, "SandboxKey": "/var/run/docker/netns/1123e52e7459", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "", "Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "", "IPPrefixLen": 0, "IPv6Gateway": "", "MacAddress": "", "Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "bb6cb306d6052a81de21c664211c4eafa397dca82b8b690a60d8c7e870413a69", "EndpointID": "", "Gateway": "", "IPAddress": "", "IPPrefixLen": 0, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "", "DriverOpts": null } } } } ] 長ったらしいJSONですが、すべてを見る必要はありません。必要なところだけ見ていきます。 コマンド 「/var/rapid/aws-lambda-rie --log-level error」であることがここでも確認できます。 "Path": "/var/rapid/aws-lambda-rie", "Args": [ "--log-level", "error" ] ポートバインディング ホストの127.0.0.1:5018にバインドしているようです。ポートはランダムになるみたいなので、実際に動かすときは任意のポートにできると思います。IPが127.0.0.1なので、この設定では外部からアクセスできません。 "PortBindings": { "8080/tcp": [ { "HostIp": "127.0.0.1", "HostPort": "5018" } ] } メモリ容量 後述の環境変数でも指定されていますが、128MBが割り当てられているようです。 "Memory": 134217728 環境変数 色々設定されていますが、先ほど確認したコンテナのhistoryの情報からLANGから下はイメージ側で設定されていることがすでに判明していますので、コンテナを作成する際は「AWS」から始まるものを設定すればよさそうです。 "Env": [ "AWS_SAM_LOCAL=true", "AWS_LAMBDA_FUNCTION_MEMORY_SIZE=128", "AWS_LAMBDA_FUNCTION_TIMEOUT=3", "AWS_LAMBDA_FUNCTION_HANDLER=app.lambda_handler", "AWS_LAMBDA_FUNCTION_NAME=HelloWorldFunction", "AWS_LAMBDA_FUNCTION_VERSION=$LATEST", "AWS_LAMBDA_LOG_GROUP_NAME=aws/lambda/HelloWorldFunction", "AWS_LAMBDA_LOG_STREAM_NAME=$LATEST", "AWS_REGION=us-east-1", "AWS_DEFAULT_REGION=us-east-1", "AWS_ACCESS_KEY_ID=defaultkey", "AWS_SECRET_ACCESS_KEY=defaultsecret", "AWS_ACCOUNT_ID=123456789012", "LANG=en_US.UTF-8", "TZ=:/etc/localtime", "PATH=/var/lang/bin:/usr/local/bin:/usr/bin/:/bin:/opt/bin", "LD_LIBRARY_PATH=/var/lang/lib:/lib64:/usr/lib64:/var/runtime:/var/runtime/lib:/var/task:/var/task/lib:/opt/lib", "LAMBDA_TASK_ROOT=/var/task", "LAMBDA_RUNTIME_DIR=/var/runtime" ] 環境変数 値(例) 説明 AWS_SAM_LOCAL true SAM LOCALで実行しているかを示す模様 AWS_LAMBDA_FUNCTION_MEMORY_SIZE 128 メモリサイズ(MB) AWS_LAMBDA_FUNCTION_TIMEOUT 3 関数実行タイムアウト時間 AWS_LAMBDA_FUNCTION_HANDLER app.lambda_handler ハンドラ(後述) AWS_LAMBDA_FUNCTION_NAME HelloWorldFunction Lambda関数名 AWS_LAMBDA_FUNCTION_VERSION $LATEST Lambda関数のバージョン AWS_LAMBDA_LOG_GROUP_NAME aws/lambda/HelloWorldFunction ロググループ名 AWS_LAMBDA_LOG_STREAM_NAME $LATEST ログストリーム名 AWS_REGION us-east-1 リージョン AWS_DEFAULT_REGION us-east-1 デフォルトリージョン AWS_ACCESS_KEY_ID defaultkey IAMアクセスキー AWS_SECRET_ACCESS_KEY defaultsecret IAMシークレットキー AWS_ACCOUNT_ID 123456789012 AWSアカウントID マウント情報 SourceにSAM CLIでビルドしたLambda関数のディレクトリが読み取り専用で指定されています。つまり、コンテナと作成したコードを紐づける、一番重要な部分になります。 "Mounts": [ { "Type": "bind", "Source": "/home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction", "Destination": "/var/task", "Mode": "ro,delegated", "RW": false, "Propagation": "rprivate" } ], Sourceに指定されているディレクトリを確認すると、以下のような結果が得られます。 $ ls -l /home/izayoiwind/workspaces/sam-workspaces/sam-py/.aws-sam/build/HelloWorldFunction 合計 16 -rw-rw-r-- 1 izayoiwind izayoiwind 0 4月 17 08:23 __init__.py -rw-rw-r-- 1 izayoiwind izayoiwind 1151 4月 17 08:23 app.py drwxrwxr-x 2 izayoiwind izayoiwind 77 4月 17 08:23 certifi drwxrwxr-x 2 izayoiwind izayoiwind 85 4月 17 08:23 certifi-2020.12.5.dist-info drwxrwxr-x 4 izayoiwind izayoiwind 4096 4月 17 08:23 chardet drwxrwxr-x 2 izayoiwind izayoiwind 109 4月 17 08:23 chardet-4.0.0.dist-info drwxrwxr-x 2 izayoiwind izayoiwind 155 4月 17 08:23 idna drwxrwxr-x 2 izayoiwind izayoiwind 89 4月 17 08:23 idna-2.10.dist-info drwxrwxr-x 2 izayoiwind izayoiwind 4096 4月 17 08:23 requests drwxrwxr-x 2 izayoiwind izayoiwind 85 4月 17 08:23 requests-2.25.1.dist-info -rw-rw-r-- 1 izayoiwind izayoiwind 8 4月 17 08:23 requirements.txt drwxrwxr-x 5 izayoiwind izayoiwind 272 4月 17 08:23 urllib3 drwxrwxr-x 2 izayoiwind izayoiwind 133 4月 17 08:23 urllib3-1.26.4.dist-info app.pyの内容は以下の通りです。 app.py import json # import requests def lambda_handler(event, context): """Sample pure Lambda function Parameters ---------- event: dict, required API Gateway Lambda Proxy Input Format Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format context: object, required Lambda Context runtime methods and attributes Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html Returns ------ API Gateway Lambda Proxy Output Format: dict Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html """ # try: # ip = requests.get("http://checkip.amazonaws.com/") # except requests.RequestException as e: # # Send some context about this error to Lambda Logs # print(e) # raise e return { "statusCode": 200, "body": json.dumps({ "message": "hello world", # "location": ip.text.replace("\n", "") }), } 環境変数のハンドラの指定について では、ここで環境変数のハンドラの指定を見てみましょう。以下のように指定されています。 app.lambda_handler これを踏まえて、上記のapp.pyのコードを見ると、以下のように指定するということが分かります。 <拡張子を除いたソースファイル>.<関数名> よろしい、ならば手動で動かすまでだ ここまで得た情報で、実際にSAM CLIを使わずに動かすことができます。 せっかくなので、SAM CLIで作ったものではなく、独自で作ってみます。以下のコードをi_want_five_quadrillion_yen.pyという名前で保存します。(エラー処理等は特に考えてません、さらに筆者はPythonに関しては初心者レベルですので悪しからず) # coding: utf-8 import json def lambda_func(event, context): output = '{}兆円欲しい!'.format(event['input']) return { 'output': output, } 保存先は/home/izayoiwind/i_want_five_quadrillion_yen/としています。 それでは、コンテナを起動します。 $ sudo docker run -d -m "128M" \ -e AWS_SAM_LOCAL=true \ -e AWS_LAMBDA_FUNCTION_MEMORY_SIZE=128 \ -e AWS_LAMBDA_FUNCTION_TIMEOUT=3 \ -e AWS_LAMBDA_FUNCTION_HANDLER=i_want_five_quadrillion_yen.lambda_func \ -e AWS_LAMBDA_FUNCTION_NAME=IWantFiveQuadrillionYen \ -e AWS_LAMBDA_FUNCTION_VERSION=$LATEST \ -e AWS_LAMBDA_LOG_GROUP_NAME=aws/lambda/IWantFiveQuadrillionYen \ -e AWS_LAMBDA_LOG_STREAM_NAME=$LATEST \ -e AWS_REGION=us-east-1 \ -e AWS_DEFAULT_REGION=us-east-1 \ -e AWS_ACCESS_KEY_ID=defaultkey \ -e AWS_SECRET_ACCESS_KEY=defaultsecret \ -e AWS_ACCOUNT_ID=123456789012 \ -p 8080:8080 \ -v /home/izayoiwind/i_want_five_quadrillion_yen:/var/task:ro,delegated \ amazon/aws-sam-cli-emulation-image-python3.7:rapid-1.22.0 \ /var/rapid/aws-lambda-rie --log-level error 起動後、curlで以下のURLを叩くと、Lambda関数が実行されます。Pythonの場合、マルチバイト文字を入れるとUnicodeエスケープシーケンスで返されるようなので、応答結果にちょっと細工をいれています。 $ curl -XPOST "http://localhost:8080/2015-03-31/functions/function/invocations" -s -d '{"input": "5000"}' | python -c 'from sys import stdin; print stdin.readline().decode("unicode-escape")' {"output": "5000兆円欲しい!"} 【おまけ】作成したコンテナの関数をAWS CLIから叩いてみる ところで、先ほど出てきた以下のURLですが、このURLはAWS CLIでLambda関数を叩くときのURLと同様です。 なので、AWS CLIからも叩くことが可能です。 以下のコマンドで叩くことができます。(関係ないけどAmazon Linux 2イメージに含まれるAWS CLIは1.x系のようです) $ aws --endpoint-url http://localhost:8080 lambda invoke --function-name function --payload '{"input":"5000"}' ./test.txt { "StatusCode": 200 } $ cat ./test.txt | python -c 'from sys import stdin; print stdin.readline().decode("unicode-escape")' {"output": "5000兆円欲しい!"} AWS CLI 2.x系の場合はpayloadにbase64エンコードした文字列を指定します。AWS CLI 2.x系を入れていた環境がPython 3系だったため、Unicodeエスケープ関連の処理を少し変えています。 $ echo {\"input\":\"5000\"} | base64 eyJpbnB1dCI6IjUwMDAifQo= $ aws --endpoint-url http://amzn.izayoiwind.net:8080 lambda invoke --function-name function --payload eyJpbnB1dCI6IjUwMDAifQo= ./test.txt { "StatusCode": 200 } $ cat test.txt | python -c 'from sys import stdin; print(stdin.readline().encode("utf-8").decode("unicode-escape"));' {"output": "5000兆円欲しい!"} 注意点として、本家AWS LambdaをCLI経由で呼び出した場合、レスポンスにX-Amz-Function-Errorヘッダが含まれるため、以下のようにFunctionErrorが通知されますが、エミュレータでの実行の場合、実行に失敗してもレスポンスにX-Amz-Function-Errorヘッダが含まれないようで、ステータスコード以外の情報は一切通知されません。 $ aws lambda invoke --function-name i_want_five_quadrillio n_yen ./test.txt { "FunctionError": "Unhandled", "ExecutedVersion": "$LATEST", "StatusCode": 200 }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【AWS】RDSについてまとめてみた

RDSとは? マネージド型データベースサービスです。 EC2にデータベースの高度な機能が付加されています。 リレーショナルデータベースの構築にはRDSが使われます。 Amazon RDSは、PaaSと呼ばれるサービスの1種です。 ApplicationとData以外はAmazonが“サービスとして提供”しています。 つまり、あらかじめセットアップされた状態で提供され、バックアップなどもAWSが運用してくれるため、 ストレスなく使うことができます。 RDSはEC2の進化形 RDSはEC2に6つの要素を足したものです。 ①エンジンの選択 計6つの中から選択できます。 ・Amazon Aurora ・PostgreSQL ・MySQL ・MariaDB ・ORACLE ・SQLServer ②エンドポイント通信 障害が起きた際に親のRDSが使えなくなった際に、 自動で子のRDSの方に接続してくれる機能です。 ③リードレプリカ DBに参照用と更新用に分けて運用することができる機能です。 これを分けることによって、負荷分散が可能となります。 ④自動スナップショット バックアップの機能があります。 ⑤自動パッチ セキュリティの機能があります。 ⑥パラメーター設定 パラメーターグループを作って設定値を変えることができます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【育児負荷低減の為のエンジニアリングその2 ポケモンしりとり編 AWS S3 lambda api-gateway terraform】

何を作ったか ポケモンの名前を入力すると、自動的にしりとりをしてくれる物を作りました。 AIとかそんな大それたもの入ってないです。ランダムで対象のポケモンを繋いでいくものです。 しりとりモード ふつうにしりとり 最初と最後のポケモンを入力すると勝手にしりとりやってくれます にゅうりょくもじからはじまるポケモン 入力文字から始まるポケモンを返してくれます どこかにもじがはいるポケモン(尻じゃないですが) 入力文字が含まれているポケモンを返してくれます にゅうりょくもじでおわるポケモン 入力文字で終わるポケモンを返してくれます 何故作ろうと思ったか https://qiita.com/zukaishi/items/7bcb16fb57fdcd762914 - 前回のこちらと同じ理由になりますが、あまりにもしりとりをする事を要求されることに疲れました - ポケモンにハマっている息子(小学1年性)がたくさんポケモンの名前を覚えたのでそれをアピールしたいんでしょうね。そのためしりとり、毎日のように勝負を挑んでくるが面倒になってしまったので、ポケモンしりとりを勝手にしてくれるものをつくりました。 - そんなにポケモン知らないし、そもそも赤・緑で知識が止まっている状態ですし、、、。 どのように実現したか アーキテクチャ AWSとTerraformの勉強がてらこんなアーキテクチャで作ってみました。 AWSでホスティングさせるための実際にブラウザでアクセスするindexとしりとりの対象にするリストをあらかじめs3 bucketにあらかじめ格納しておく しりとりの核となる処理は、API-Gateway → LambdaでAPIリクエストすることによって処理される 取得された結果をブラウザが表示する AWS準備 variable "bucket_name" { default = "website.shiritori.com" } data "aws_iam_policy_document" "s3_bucket_policy" { statement { actions = ["s3:GetObject"] effect = "Allow" principals { type = "AWS" identifiers = ["*"] } resources = ["arn:aws:s3:::${var.bucket_name}/*"] sid = "PublicReadGetObject" } } resource "aws_s3_bucket" "website_shiritori_com" { bucket = var.bucket_name policy = data.aws_iam_policy_document.s3_bucket_policy.json website { index_document = "index.html" error_document = "error.html" } } resource "aws_s3_bucket_public_access_block" "website_shiritori" { bucket = var.bucket_name block_public_acls = true block_public_policy = false ignore_public_acls = true restrict_public_buckets = false } output "url" { value = aws_s3_bucket.website_shiritori_com.website_endpoint } データ取得 func comprised(word string) string { url := "https://s3-ap-northeast-1.amazonaws.com/website.shiritori.com/data/pokemon_list.csv" resp, err := http.Get(url) if err != nil { fmt.Println(err) } defer resp.Body.Close() reader := csv.NewReader(resp.Body) pokemonList := map[int]string{} for { record, err := reader.Read() if err == io.EOF { break } if err != nil { log.Fatal(err) } var i int i, _ = strconv.Atoi(record[0]) pokemonList[i] = record[1] } result := "" for key, value := range pokemonList { if strings.Contains(value, word) { result += fmt.Sprintf("%d:%s", key, value) result += "," } } return result } メイン部 func shiritori(name1 string, name2 string) string { url := "https://s3-ap-northeast-1.amazonaws.com/website.shiritori.com/data/pokemon_list.csv" resp, err := http.Get(url) if err != nil { fmt.Println(err) } defer resp.Body.Close() reader := csv.NewReader(resp.Body) pokemonList := map[int]string{} for { record, err := reader.Read() if err == io.EOF { break } if err != nil { log.Fatal(err) } if name2 == record[1] || getLastString(record[1]) != "ン" { var i int i, _ = strconv.Atoi(record[0]) pokemonList[i] = record[1] } } startNo := contains(pokemonList, name1) endNo := contains(pokemonList, name2) if startNo == 0 || endNo == 0 { fmt.Printf("input name failed ¥n") } word := "" no := startNo result := "" for { result += fmt.Sprintf("%d:%s", no, pokemonList[no]) word = pokemonList[no] delete(pokemonList, no) lastString := getLastString(word) list := containsList(pokemonList, lastString) if len(list) == 0 || endNo == no { break } result += "," if lastString == getRuneAt(name2, 0) { result += fmt.Sprintf("%d:%s", endNo, name2) break } randMap := []int{} for key := range list { randMap = append(randMap, key) } rand.Seed(time.Now().UnixNano()) randNo := rand.Intn(len(randMap)) no = randMap[randNo] } return result } 文字変換周り func getLastString(word string) string { // 対象文字の最後の文字を取得utf-8のため、/3している lastString := getRuneAt(word, len(word)/3-1) // 最後の文字が伸ばし棒の場合 if lastString == "ー" { lastString = getRuneAt(word, len(word)/3-2) } // 特殊文字、捨て仮名を扱いやすい形へ変換する r := strings.NewReplacer("♂", "ス", "♀", "ス", "ァ", "ア", "ィ", "イ", "ゥ", "ウ", "ェ", "エ", "ォ", "オ", "ュ", "ユ", "ャ", "ヤ", "ョ", "ヨ") resStr := r.Replace(lastString) return resStr } コード コードはこちらにアップしてあります。 https://github.com/zukaishi/aws_shiritori 使い方 https://s3-ap-northeast-1.amazonaws.com/website.shiritori.com/index.html 結果どうなったか その度にiPadをせがまれるようになって助かったのはいいのですが、僕がその時間iPad使えないのでちょっと不便、、、。 子供はキーボード叩いたりできないのでちょいちょい打ち込むのが面倒 あと、ポケモンのブームが過ぎ去って、今度はLEGOブームが到来です。 LEGOを自動化するものは、、、。ハードルが高いなぁと思う今日この頃です。 今後やりたいこと 最短、最長の経路を選択できるようにしたい イラストとか引っ張ってこれるようにしたい terraformでapi-gateway周りも実現できるようにしたい ポケモン名前を選択できるようにする or 音声入力を可能にするか
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AWS CloudFormationでLambdaを使用するAPI Gatewayを構築しよう

はじめに AWS CloudFormationを利用してLambdaを使用するAPI Gateway構築のテンプレートのサンプルです。 Lambdaは、S3アーティファクトを使用します。 テンプレートの概要が分からない場合は、はじめてのAWS CloudFormationテンプレートを理解するを参考にしてください。 コードはGitHubにもあります。 今回は、akane というシステムの dev 環境を想定しています。 同じ構成で違う環境を作成する場合は、{環境名}-parameters.jsonを別途作成します。 ディレクトリ構成 akane (システム) ├── apigw (スタック) │ ├── apigw.yml (CFnテンプレート) │ └── dev-parameters.json (dev 環境のパラメータ) ├── lambda (スタック) │ ├── code │ │ └── getTiAmo.py (S3アーティファクトソース) │ ├── code-lambda-getTiAmo.zip (S3アーティファクト) │ ├── delete_artifact.dev.sh (S3アーティファクト削除シェル) │ ├── dev-parameters.json (dev 環境のパラメータ) │ ├── lambda.yml (CFnテンプレート) │ ├── mkzip.sh (S3アーティファクト作成シェル) │ └── upload_artifact.dev.sh (S3アーティファクト削除シェル) └─ s3 (スタック) ├─ s3.yml (CFnテンプレート) └─ all-parameters.json (all 環境のパラメータ) AWS リソース構築内容 apigwスタック CloudWatch ログのロール API Gateway 使用量プラン API キー lambdaスタック Lambdaロール Lambda s3スタック s3バケット (akane-all-s3-artifacts) バケットポリシー (s3:GetObject) 実行環境の準備 AWS CloudFormationを動かすためのAWS CLIの設定を参考にしてください。 AWS リソース構築手順 下記を実行してスタックを作成 ./create_stacks.sh 下記を実行してLambdaの動作を確認 ./test_lambda.sh 下記を実行してAPI Gatewayの動作を確認 ./test_apigw.sh <URL> <API_KEY> 下記を実行してスタックを削除 ./delete_stacks.sh 構築テンプレート 1. s3スタック s3.yml AWSTemplateFormatVersion: 2010-09-09 Description: S3 For Akane # Metadata: Parameters: SystemName: Type: String AllowedPattern: '[a-zA-Z0-9-]*' EnvType: Description: Environment type. Type: String AllowedValues: [all, dev, stg, prod] ConstraintDescription: must specify all, dev, stg, or prod. # Mappings # Conditions # Transform Resources: # S3 Bucket作成 akaneS3Bucket: Type: AWS::S3::Bucket Properties: AccessControl: Private BucketName: !Sub - ${SystemName}-${EnvType}-s3-artifacts - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} Tags: - Key: Name Value: !Sub - ${SystemName}-${EnvType}-s3-artifacts - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} - Key: SystemName Value: !Ref SystemName - Key: EnvType Value: !Ref EnvType # S3 BucketPolicy作成 akaneS3BucketPolicy: Type: AWS::S3::BucketPolicy DependsOn: akaneS3Bucket Properties: Bucket: !Ref akaneS3Bucket PolicyDocument: Statement: - Action: - s3:GetObject Effect: Allow Resource: !Join - '' - - 'arn:aws:s3:::' - !Ref akaneS3Bucket - /* Principal: AWS: '*' Outputs: akaneS3Bucket: Value: !Ref akaneS3Bucket Export: Name: !Sub - ${SystemName}-${EnvType}-s3-artifacts - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} all-parameters.json { "Parameters": [ { "ParameterKey": "SystemName", "ParameterValue": "akane" }, { "ParameterKey": "EnvType", "ParameterValue": "all" } ] } 2. lambdaスタック lambda.yml AWSTemplateFormatVersion: 2010-09-09 Description: Lambda For Akane # Metadata: Parameters: SystemName: Type: String AllowedPattern: '[a-zA-Z0-9-]*' EnvType: Description: Environment type. Type: String AllowedValues: [all, dev, stg, prod] ConstraintDescription: must specify all, dev, stg, or prod. ArtifactS3Bucket: Type: String LambdaName: Type: String LambdaMemorySize: Type: Number LambdaRuntime: Type: String GirlName: Type: String # Mappings # Conditions # Transform Resources: # ロール作成 akaneRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Description: !Sub - ${SystemName}-${EnvType}-role-lambda-${AWS::Region} - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Path: / RoleName: !Sub - ${SystemName}-${EnvType}-role-lambda-${AWS::Region} - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} Tags: - Key: Name Value: !Sub - ${SystemName}-${EnvType}-role-lambda-${AWS::Region} - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} - Key: SystemName Value: !Ref SystemName - Key: EnvType Value: !Ref EnvType # Lambda作成 akaneLambdaGetTiAmo: Type: AWS::Lambda::Function Properties: Code: S3Bucket: !Ref ArtifactS3Bucket S3Key: !Sub - code-lambda-${LambdaName}.zip - {LambdaName: !Ref LambdaName} Description: !Sub - ${SystemName}-${EnvType}-lambda-${LambdaName} - {SystemName: !Ref SystemName, EnvType: !Ref EnvType, LambdaName: !Ref LambdaName} Environment: Variables: GIRL_NAME: !Ref GirlName FunctionName: !Sub - ${SystemName}-${EnvType}-lambda-${LambdaName} - {SystemName: !Ref SystemName, EnvType: !Ref EnvType, LambdaName: !Ref LambdaName} Handler: !Sub - ${LambdaName}.handler - {LambdaName: !Ref LambdaName} MemorySize: !Ref LambdaMemorySize Role: !GetAtt akaneRole.Arn Runtime: !Ref LambdaRuntime Tags: - Key: Name Value: !Sub - ${SystemName}-${EnvType}-lambda-${LambdaName} - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} - Key: SystemName Value: !Ref SystemName - Key: EnvType Value: !Ref EnvType Timeout: 900 TracingConfig: Mode: PassThrough Outputs: akaneLambdaGetTiAmoArn: Value: !GetAtt akaneLambdaGetTiAmo.Arn Export: Name: !Sub - ${SystemName}-${EnvType}-lambda-arn - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} dev-parameters.json { "Parameters": [ { "ParameterKey": "SystemName", "ParameterValue": "akane" }, { "ParameterKey": "EnvType", "ParameterValue": "dev" }, { "ParameterKey": "ArtifactS3Bucket", "ParameterValue": "akane-all-s3-artifacts" }, { "ParameterKey": "LambdaName", "ParameterValue": "getTiAmo" }, { "ParameterKey": "LambdaMemorySize", "ParameterValue": "128" }, { "ParameterKey": "LambdaRuntime", "ParameterValue": "python3.8" }, { "ParameterKey": "GirlName", "ParameterValue": "akane" } ], "Capabilities": [ "CAPABILITY_NAMED_IAM" ] } 3. apigwスタック apigw.yml AWSTemplateFormatVersion: 2010-09-09 Description: API Gateway For Akane # Metadata: Parameters: SystemName: Type: String AllowedPattern: '[a-zA-Z0-9-]*' EnvType: Description: Environment type. Type: String AllowedValues: [all, dev, stg, prod] ConstraintDescription: must specify all, dev, stg, or prod. EnvTypeCommon: Description: Environment type. Type: String AllowedValues: [all, dev, stg, prod] ConstraintDescription: must specify all, dev, stg, or prod. APIPathPart: Type: String APIGatewayStage: Type: String # Mappings # Conditions # Transform Resources: # ApiGateway CloudWatchRole 作成 akaneCloudWatchRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - apigateway.amazonaws.com Action: sts:AssumeRole Description: !Sub - ${SystemName}-${EnvTypeCommon}-role-apigw-cloudwatch-${AWS::Region} - {SystemName: !Ref SystemName, EnvTypeCommon: !Ref EnvTypeCommon} ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs Path: / RoleName: !Sub - ${SystemName}-${EnvTypeCommon}-role-apigw-cloudwatch-${AWS::Region} - {SystemName: !Ref SystemName, EnvTypeCommon: !Ref EnvTypeCommon} Tags: - Key: Name Value: !Sub - ${SystemName}-${EnvTypeCommon}-role-apigw-cloudwatch-${AWS::Region} - {SystemName: !Ref SystemName, EnvTypeCommon: !Ref EnvTypeCommon} - Key: SystemName Value: !Ref SystemName - Key: EnvTypeCommon Value: !Ref EnvTypeCommon akaneApiGatewayAccount: Type: AWS::ApiGateway::Account Properties: CloudWatchRoleArn: !GetAtt akaneCloudWatchRole.Arn # ApiGateway 作成 akaneApiGateway: Type: AWS::ApiGateway::RestApi DependsOn: akaneApiGatewayAccount Properties: Name: !Sub - ${SystemName}-${EnvType}-apigw - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} Description: !Sub - ${SystemName}-${EnvType}-apigw - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} EndpointConfiguration: Types: - REGIONAL Tags: - Key: Name Value: !Sub - ${SystemName}-${EnvType}-apigw - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} - Key: SystemName Value: !Ref SystemName - Key: EnvType Value: !Ref EnvType akaneApiGatewayResource: Type: AWS::ApiGateway::Resource Properties: RestApiId: !Ref akaneApiGateway ParentId: !GetAtt akaneApiGateway.RootResourceId PathPart: !Ref APIPathPart akaneApiGatewayLambdaPermission: Type: AWS::Lambda::Permission Properties: FunctionName: Fn::ImportValue: !Sub - ${SystemName}-${EnvType}-lambda - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} Action: lambda:InvokeFunction Principal: apigateway.amazonaws.com akaneApiGatewayResourceMethod: Type: AWS::ApiGateway::Method DependsOn: akaneApiGatewayLambdaPermission Properties: RestApiId: !Ref akaneApiGateway ResourceId: !Ref akaneApiGatewayResource ApiKeyRequired: true AuthorizationType: NONE HttpMethod: GET Integration: Type: AWS_PROXY IntegrationHttpMethod: POST Uri: !Join - '' - - 'arn:aws:apigateway:' - !Ref AWS::Region - ':lambda:path/2015-03-31/functions/' - Fn::ImportValue: !Sub - ${SystemName}-${EnvType}-lambda-arn - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} - '/invocations' akaneApiGatewayDeployment: Type: AWS::ApiGateway::Deployment DependsOn: akaneApiGatewayResourceMethod Properties: Description: !Sub - ${SystemName}-${EnvType}-apigw-deployment - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} RestApiId: !Ref akaneApiGateway akaneApiGatewayStage: Type: AWS::ApiGateway::Stage DependsOn: akaneApiGatewayDeployment Properties: DeploymentId: !Ref akaneApiGatewayDeployment Description: !Sub - ${SystemName}-${EnvType}-apigw-stage - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} MethodSettings: - CacheDataEncrypted: false CachingEnabled: false DataTraceEnabled: true # CloudWatch ログを有効化 HttpMethod: '*' LoggingLevel: ERROR MetricsEnabled: false # 詳細 CloudWatch メトリクスを有効化 ResourcePath: '/*' RestApiId: !Ref akaneApiGateway StageName: !Ref APIGatewayStage Tags: - Key: Name Value: !Sub - ${SystemName}-${EnvType}-apigw-stage - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} - Key: SystemName Value: !Ref SystemName - Key: EnvType Value: !Ref EnvType TracingEnabled: false # X-Ray トレースの有効化 # ApiGateway APIキー 作成 akaneApiGatewayKey: Type: AWS::ApiGateway::ApiKey Properties: Description: !Sub - ${SystemName}-${EnvType}-apigw-key - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} Enabled: true akaneApiGatewayUsagePlan: Type: AWS::ApiGateway::UsagePlan DependsOn: akaneApiGatewayStage Properties: ApiStages: - ApiId: !Ref akaneApiGateway Stage: !Ref APIGatewayStage Description: !Sub - ${SystemName}-${EnvType}-apigw-usage-plan - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} UsagePlanName: !Sub - ${SystemName}-${EnvType}-apigw-usage-plan - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} Tags: - Key: Name Value: !Sub - ${SystemName}-${EnvType}-apigw-usage-plan - {SystemName: !Ref SystemName, EnvType: !Ref EnvType} - Key: SystemName Value: !Ref SystemName - Key: EnvType Value: !Ref EnvType akaneApiGatewayUsagePlanKey: Type: AWS::ApiGateway::UsagePlanKey Properties: KeyId: !Ref akaneApiGatewayKey KeyType: API_KEY UsagePlanId: !Ref akaneApiGatewayUsagePlan dev-parameters.json { "Parameters": [ { "ParameterKey": "SystemName", "ParameterValue": "akane" }, { "ParameterKey": "EnvType", "ParameterValue": "dev" }, { "ParameterKey": "EnvTypeCommon", "ParameterValue": "all" }, { "ParameterKey": "APIPathPart", "ParameterValue": "whisper" }, { "ParameterKey": "APIGatewayStage", "ParameterValue": "v1" } ], "Capabilities": [ "CAPABILITY_NAMED_IAM" ] } 4. 実行ファイル create_stacks.sh #!/bin/sh cd `dirname $0` SYSTEM_NAME=akane create_stack () { ENV_TYPE=$1 STACK_NAME=$2 aws cloudformation create-stack \ --stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME} \ --template-body file://./${SYSTEM_NAME}/${STACK_NAME}/${STACK_NAME}.yml \ --cli-input-json file://./${SYSTEM_NAME}/${STACK_NAME}/${ENV_TYPE}-parameters.json aws cloudformation wait stack-create-complete \ --stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME} } create_stack all s3 ./akane/lambda/mkzip.sh ./akane/lambda/upload_artifact.dev.sh create_stack dev lambda create_stack dev apigw exit 0 test_lambda.sh #!/bin/sh cd `dirname $0` echo " --- \033[0;33m TEST LAMBDA \033[0;39m --- " LAMBDA_NAME=akane-dev-lambda-getTiAmo OUTPUT_FILE=response.json aws lambda invoke --function-name ${LAMBDA_NAME} --log-type Tail ${OUTPUT_FILE} --query 'LogResult' --output text | base64 -D cat ${OUTPUT_FILE} exit 0 test_apigw.sh #!/bin/sh set -e if [ $# -ne 2 ]; then echo " --- \033[0;31m [ERROR]: The following arguments are required \033[0;39m --- " echo " \033[0;33m$0 <URL> <API_KEY>\033[0;39m" echo " \033[0;33m<URL> Example: https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/v1/whisper\033[0;39m" exit 1 fi cd `dirname $0` echo " --- \033[0;33m TEST APIGW \033[0;39m --- " URL=$1 API_KEY=$2 curl -X GET -H 'Content-Type: application/json' \ -H "x-api-key: ${API_KEY}" \ "${URL}" exit 0 delete_stacks.sh #!/bin/sh cd `dirname $0` SYSTEM_NAME=akane delete_stack () { ENV_TYPE=$1 STACK_NAME=$2 aws cloudformation delete-stack \ --stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME} aws cloudformation wait stack-delete-complete \ --stack-name ${SYSTEM_NAME}-${ENV_TYPE}-${STACK_NAME} } delete_stack dev apigw delete_stack dev lambda ./akane/lambda/delete_artifact.dev.sh delete_stack all s3 exit 0 4. アーティファクト関連ファイル mkzip.sh #!/bin/sh cd `dirname $0` ENV_TYPE=dev LAMBDA_NAME=$(cat ${ENV_TYPE}-parameters.json | jq -r '.Parameters[] | select(.ParameterKey == "LambdaName").ParameterValue') FILE=../code-lambda-${LAMBDA_NAME}.zip cd ./code ls . | grep -v -E ".gitignore|${LAMBDA_NAME}.py" | xargs rm -rf rm -f ${FILE} zip -r ${FILE} ./* exit 0 upload_artifact.dev.sh #!/bin/sh cd `dirname $0` BASENAME=$(basename $0) FILENAME=${BASENAME%.*} ENV_TYPE=${FILENAME##*.} BUCKET_NAME=$(cat ${ENV_TYPE}-parameters.json | jq -r '.Parameters[] | select(.ParameterKey == "ArtifactS3Bucket").ParameterValue') ARTIFACT_NAME=code-lambda-$(cat ${ENV_TYPE}-parameters.json | jq -r '.Parameters[] | select(.ParameterKey == "LambdaName").ParameterValue') aws s3 cp ${ARTIFACT_NAME}.zip s3://${BUCKET_NAME}/${ARTIFACT_NAME}.zip exit 0 delete_artifact.dev.sh #!/bin/sh cd `dirname $0` BASENAME=$(basename $0) FILENAME=${BASENAME%.*} ENV_TYPE=${FILENAME##*.} BUCKET_NAME=$(cat ${ENV_TYPE}-parameters.json | jq -r '.Parameters[] | select(.ParameterKey == "ArtifactS3Bucket").ParameterValue') ARTIFACT_NAME=code-lambda-$(cat ${ENV_TYPE}-parameters.json | jq -r '.Parameters[] | select(.ParameterKey == "LambdaName").ParameterValue') aws s3 rm s3://${BUCKET_NAME}/${ARTIFACT_NAME}.zip exit 0
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CloudFront Functionsを触ってみる

はじめに ゴールデンウィーク中暇だったので、AWSが新たに発表したCloudFrontFunctionsを触ってみました。 CloudFrontFunctionsを使用することでLambda@Edgeより前でシンプルな処理を実行できます。 参考資料::AWS公式ブログ CloudFront Functions Lambda@Edge Runtime support JavaScript(ECMAScript 5.1 compliant) Node.js, Python Execution location 218+ CloudFront Edge Locations 13 CloudFront Regional Edge Caches CloudFront triggers supported Viewer request, Viewer response Viewer request, Viewer response, Origin request, Origin response Maximum execution time Less than 1 millisecond 5 seconds (viewer triggers)30 seconds (origin triggers) Maximum memory 2MB 128MB (viewer triggers)10GB (origin triggers) Total package size 10KB 1 MB (viewer triggers), 50 MB (origin triggers) Network access no yes File system access no yes Access to the request body no yes Pricing Free tier available;charged per request No free tier; charged per request and function duration
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む