- 投稿日:2021-08-27T22:27:13+09:00
CloudWatchLogsに「AWS以外のサーバ環境」からは書き込みが出来て「AWS Fargate」からは書き込みが出来ない時の対応
CloudWatch Agent や AWS SDK を使用してCloudWatch Logsに書き込みをする際の話になります。 ローカルのDocker環境やさくらサーバなどでは動作してもAWS Fargateでは動作しなくて困ることがあるかもしれません。 上記でロググループが存在しない際にCreateLogGroupで権限エラーと表示される場合、権限&ポリシー設定になります。 IAMでログ関係の権限を全て与えているから問題が無いと勘違いをされている方もいます。 ※AWSをメインで対応している会社でも勘違いをしている方がいました。 VPCのエンドポイントのポリシーを疑うと解決するかもしれません。 ■CloudWatch Agent VPCのポリシーに下記権限を与えれば、基本的には問題が無いと思います。 # ロググループの作成 CreateLogGroup # ログストリームの作成 CreateLogStream # ログの書込 PutLogEvents # ※ログの自動削除を行う場合、削除の権限が必要になるかと思います ■AWS SDK(CloudWatch) VPCのポリシーに下記権限を与えれば、基本的には問題が無いと思います。 ※ PHPの場合、maxbanton/cwh/src/Handler/CloudWatch.phpを参照 # ロググループの作成 CreateLogGroup # ログストリームの作成 CreateLogStream # ログの書込 PutLogEvents # ロググループに「期限」を設定する場合に必要 # ※指定のロググループが存在しない場合のみ処理が実行されます PutRetentionPolicy # ロググループの一覧を取得 # ※指定のロググループの存在を確認する際に使用 DescribeLogGroups # ログストリームの一覧を取得 # ※指定のログストリームの存在を確認する際に使用 DescribeLogStreams # タグを登録 # ※指定のタグをロググループに登録する際に使用 # ※タグの指定が無ければ不要 TagLogGroup ■参照
- 投稿日:2021-08-27T22:06:36+09:00
AWSと比較したOCIの特徴①
はじめに OCI(Oracle Cloud Infrastructure)の機能、サービスをAWSと比較しながら整理したいと思います。AWSが一番機能も豊富でシェアも高いので、AWSをベースに比較していくとわかりやすいかなと思って作りました。 AWS SAAの範囲で「AWSの○○はOCIだとXX」みたいに比較していきます。 今回は「1. グローバルインフラ構成」「2. VPC/VCN」になります。 なお、以降の記載は私の理解をまとめたものです。誤っていることがあったらごめんなさい。 参考資料 AWS認定資格試験テキスト AWS認定ソリューションアーキテクト - アソシエイト Oracle Cloud Infrastructure徹底入門 Oracle Cloudの基本からインフラ設計・構築まで 目次 グローバルインフラ構成 VPC/VCN コンピューティング(TBD) ストレージ(TBD) ネットワークとコンテンツ配信(TBD) 運用支援サービス(TBD) データベース(TBD) セキュリティとアイデンティティ(TBD) アプリケーションサービス(TBD) 開発者ツール(TBD) プロビジョニングサービス(TBD) 分析サービス(TBD) 1. グローバルインフラ構成 AWS OCI 1 リージョン リージョン 2 アベイラビリティゾーン(AZ) 可用性ドメイン(AD) 3 - フォルト・ドメイン 1-1. リージョン AWS/OCIがサービスを提供している拠点(国/地域)のこと。 AWSは25、OCIは商用とGovernment合わせて30あるようです。(2021年8月25日現在) AWS:グローバルインフラストラクチャ OCI:リージョンおよび可用性ドメイン 1-2. アベイラビリティゾーン(AZ)/可用性ドメイン(AD) リージョン内にあるデータセンターのこと。一つのリージョンには複数の独立したAZ/ADがある。 ただし、OCIはまだシングルADのリージョンが多い。東京、大阪リージョンはシングルAD AWSはほとんど(全て?)のリージョンがマルチAZ 個人的にはADと言うと「Active Directory」を思い浮かべるので、ややこしく感じる。 1-3. フォルト・ドメイン フォルト・ドメインは、AD内のハードウェアのセットのこと。各可用性ドメインには3つのフォルト・ドメインがある。 サーバなどのハードウェア障害やメンテナンスは他のフォルト・ドメインには影響を与えないが、データセンター全体の障害は救えない。 AWSにはない概念? 2. VPC/VCN AWS/OCIのリソースを作っていく際に、まず初めに作るであろうVPC/VCN周りを比較します。 AWS OCI 1 VPC(Virtual Private Cloud) VCN(Virtual Cloud Network) 2 ルートテーブル ルート表 3 セキュリティグループ ネットワークセキュリティグループ 4 ネットワークACL セキュリティリスト 5 インターネットゲートウェイ インターネットゲートウェイ 6 仮想プライベートゲートウェイ 動的ルーティングゲートウェイ 7 NATゲートウェイ NATゲートウェイ 8 VPCエンドポイント サービスゲートウェイ 9 VPCピアリング ピアリング 10 Direct Connect FastConnect 11 Transit Gateway 動的ルーティングゲートウェイ 2-1. VPC/VCN 各利用者専用のプライベートなネットワーク空間をAWS/OCI内に作成するサービス。 リージョン内の複数AZ/ADにまたがって作成することで、可用性を担保できる。 リージョンをまたがってVPC/VCNを作成することはできない。 VPC/VCN設定時にCIDRブロックを設定し、その範囲内でサブネットを切って使用する。なお、AWSはAZに閉じてサブネットを設定する必要があるが、OCIはADにまたがった「リージョナルサブネット」を設定することができる。 パブリックサブネット インターネットに直接接続できるサブネット。インターネットゲートウェイやNATゲートウェイを設定することができる。 プライベートサブネット インターネットに直接接続できないサブネット。インターネットへの接続が必要な場合には、NATゲートウェイを使用したり、パブリックサブネット上の踏み台サーバを経由したりする。 AWSは明示的に「パブリックサブネット」「プライベートサブネット」を設定するのではなく、サブネット設定時にインターネットに接続できる設定(インターネットゲートウェイを設定するなど)をしたサブネットを「パブリックサブネット」としている。 OCIはサブネットの設定時に明示的に「パブリックサブネット」「プライベートサブネット」を設定する。 2-2. ルートテーブル/ルート表 サブネットごとのルーティングテーブル。 2-3. セキュリティグループ/ネットワークセキュリティグループ セキュリティグループ(AWS) EC2やELBなどのインスタンス単位で通信を制御 デフォルトではすべての通信を拒否 ステートフル インバウンド(外部からVPC内への通信)のみ設定すれば、その設定はアウトバウンド(VPCから外部への通信)にも適用される。 ネットワークセキュリティグループ(OCI) インスタンスに割り当てるVNIC単位で通信を制御 デフォルトではすべての通信を拒否 ステートレス/ステートフルどちらで設定するかを選択できる。 2-4. ネットワークACL/セキュリティリスト ネットワークACL(AWS) サブネットごとの通信を制御 デフォルトではすべての通信を許可 ステートレス インバウンド/アウトバウンドそれぞれ設定する。 セキュリティリスト サブネットごとの通信を制御 デフォルトではすべての通信を拒否 ステートレス/ステートフルどちらで設定するかを選択できる。 2-5. インターネットゲートウェイ VPC/VCNとインターネットとを接続するためのゲートウェイ 各VPC/VCNに1つだけアタッチする。 パブリックサブネットのデフォルトゲートウェイ(0.0.0.0/0)はインターネットゲートウェイに設定する 2-6. 仮想プライベートゲートウェイ/動的ルーティングゲートウェイ VPC/VCNがVPNやDirect Connect/FastConnect(専用線)と接続するためのゲートウェイ 各VPCに1つだけアタッチできる 2-7. NATゲートウェイ プライベートサブネット上のインスタンスがインターネット接続する際に利用するゲートウェイ アウトバウンド通信のみ可能 2-8. VPCエンドポイント/サービスゲートウェイ S3やDynamoDB(AWS)/オブジェクトストレージやAutonomousDB(OCI)などのVPC/VCNに属さないサービスにプライベート接続するためのゲートウェイ。 VPCエンドポイント/サービスゲートウェイを使用しない場合、VPC/VCN内のリソースがS3/オブジェクトストレージなどに接続するときには、インターネットを経由することになりセキュリティ的によろしくない。 2-9. VPCピアリング/ピアリング 異なるVPC/VCN同士を接続すること(VPCとVCNが接続できるということではない。VPC同士、VCN同士の接続) 異なるリージョン間のVPC/VCNも接続可能 2-10. Direct Connect/FastConnect 専用線接続 オンプレのデータセンターとAWS/OCIを専用線で接続することで、閉域網を構成できる。 2-11. Transit Gateway/動的ルーティングゲートウェイ これらを利用することで、複数のVPC/VCNやオンプレミス環境をハブ・アンド・スポーク構成で接続できる。
- 投稿日:2021-08-27T18:33:51+09:00
【AWS SAM】デプロイとローカル確認用のコンテナイメージを一つのDockerfileで使い分ける
初めに LambdaアプリケーションをSAMで開発するにあたりコンテナでデプロイを初めて取り扱うにあたり色々試行していたのですが、 せっかくコンテナで環境をそのまま持ってけるんだからローカル環境も同じコンテナで処理したい! でもDockerfileの多重管理はしたくない!となっていい方法がないかと模索していたところ 割と良さげな方法がありましたので備忘録がてらまとめます。 AWSのサポートに問い合わせてみたら記事執筆時点(2021/08/27)では まだ公式のドキュメントが追いついてなく記載がなく追記予定らしいです。 こんなことしなくてももっと簡単にできるよっていうのがあったらご教示いただければと思います。 何がしたかったか 今回はAWS公式で提供されているpython3.8のイメージをベースとします。 大元のDockerfileはドキュメントに記載の通り以下で ENTRYPOINT ["/lambda-entrypoint.sh"] が実装されており、これに対して CMD で引数を渡すような作りをすることで対象のスクリプトを実行できます。 https://github.com/aws/aws-lambda-base-images/blob/python3.8/Dockerfile.python3.8 ただしこのコンテナをローカル開発で利用するにあたり以下の点が不満でした sam経由で実行する場合sam build と sam local invoke が必要 せっかくのスクリプト言語なのにいちいちビルドが必要で確認がめんどくさい build問題はsamを経由せずに ボリュームをマウントdockerコマンド経由で実行してやれば解決はするが次項の問題がある コンテナは起動するとスクリプトの実行が終わるのでコンテナを立ち上げっぱなしにできない ちょっと確認のためにコンテナ内で作業したいとかがやりづらい なのでローカル用にはENTRYPOINT ["tail", "-f"]を実装したDockerfileを利用し、 通常時は内部でpythonコマンド経由で実行しある程度整理できたところで、 sam経由で実行のようなことを考えていました。 ただしこのためにDockerfileを複数作って管理というのは共通部分を多重に管理しないといけないため回避したい問題でした。 解決方法 Dockerのマルチステージビルドを使うことで解決できました。 今回調べるまで知らなかったのですがdocker build の--targetオプションで指定したステージを最終成果物としてできることを知りました。 ただdocker build --target=xxxと同じ挙動をするものがSAMに見当たらないという点でつまづきました。 sam buildのドキュメントにもなくSAMのアプリケーションビルドのページにもなかったのでAWSに問い合わせしてみたのですが、 ドキュメントが追いついていないだけでSAM CLI 1.12.0で実装されていたようです。 (SAM側のテンプレートファイルのDockerBuildTargetで利用するステージの指定が可能) https://github.com/aws/aws-sam-cli/issues/2578 各種実装 ファイルの配置 testフォルダとか一部省略してます。 docker-compose.ymlが増えている以外はsam initで作られるのと同じです。 . ├── src │ ├── Dockerfile │ ├── docker-compose.yml │ ├── __init__.py │ ├── requirements.txt │ └── app.py └── template.yaml Dockerfileの実装 最初にデプロイ用のprodイメージを作り、 その後にそこからローカル開発用に一部を書き換えたdevイメージを作成します。 Dockerfile FROM public.ecr.aws/lambda/python:3.8 as prod #ソースコード類をコピー COPY ./* ./ RUN python3.8 -m pip install -r requirements.txt CMD ["app.lambda_handler"] FROM prod AS dev ENTRYPOINT [ "tail", "-f"] docker-compose.yml 個人的にはdocker-compose経由の起動が楽なのでdocker-compose.ymlも作っておきます。 このdocker-compose.ymlはローカルの開発専用でSAMでデプロイする場合は後述のSAMテンプレート側が読まれます。 target: devを指定することでdocker-compose経由で起動する場合はdev側のイメージを利用します。 docker-compose.yml version: "3" services: app: build: context: . dockerfile: Dockerfile target: dev volumes: - .:/var/task template.yml SAM側のコンテナの設定系はMetadataで設定します(詳しくはSAMのアプリケーションビルドを参照) このMetadataにDockerBuildTargetで対象のステージを指定することができるようです。 (2021/08/27時点で記載がなかったのはこのパラメータ) なおこのパラメータをなしで実行すると最終のdevまで実行されたものが利用されました。 template.ymlは以下のような形で実装します(一部省略) template.yml AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 ... Resources: CreateMntFolder: Type: AWS::Serverless::Function Properties: PackageType: Image ... Metadata: Dockerfile: Dockerfile DockerContext: ./src DockerTag: python3.8-v1 DockerBuildTarget: prod こうすることでDockerfileを多重管理する必要もなくなり、 ちょっと確認したい時はdocker-compose up -d経由でコンテナを立ち上げ、 docker-compose exec app bashで内部に入って実行もできますし、 sam buildからのsam local invokeやsam local start-api等の各種ローカル実行系のコマンドでの確認もできます。 終わりに マルチステージビルドはDocker公式チュートリアルちょっと読む限りは中間成果物があるような環境のために 使い捨ての作業イメージが作れるくらいのイメージでした。 実際はそうではなくSAMに限らずこれまで環境ごとに複数Dockerfileを作っていたのが、 一つのファイルで共通の部分の中間イメージを作りそこから個別実装ということができたり、 今回みたいに用途によって途中のステージのものを利用することもできたりと 少し視野を広く持っていればいろいろなことができそうです。 一つのDockerfileにアプリとDBのイメージを両方記載してdocker-compose.ymlでtargetパラメータをうまく指定することで Dockerfileを一つにまとめられそうなんですがどうなんでしょうか。 同じこと考えている人はいそうなのでこの辺りはまたチュートリアルとかフォーラムとか色々みてみようかと思います。
- 投稿日:2021-08-27T18:30:56+09:00
【Lambda】AWSのLambdaの設定項目について調べてみた。
はじめに 先日、業務でAWSのLambdaというサービスを使うことになり、 それについて色々調べてみました。 今回は、備忘としてLambda関数の設定項目に関する説明を記述していこうかなと思います。 Lambdaとは Lambdaとはどういったサービスなのか。 AWSの公式ページには以下のように記載されていました。 AWS Lambda はサーバーレスコンピューティングサービスで、サーバーのプロビジョニングや管理、ワークロード対応のクラスタースケーリングロジックの作成、イベント統合の維持、ランタイムの管理を行わずにコードを実行できます わざわざサーバを構築せずとも。色々なことを実行できますよー的な感じですね。 Lambda上に実行したい処理(プログラム)を定義することにより、 指定したタイミングで実行することができます。 Lambdaを利用して様々なことができる訳ですが、 どんなことが出来るかは各自で調べていただけると幸いです。。 Lambdaの設定 本題のLambdaで設定できる内容について記載していこうと思います。 なお、本記事では関数の設定項目について記載しています。 関数名 その名の通り、関数の名前を指定します。 半角英数字、ハイフン、アンダースコアのみを使用でき、スペースは使用できません。 ランタイム 関数の記述に使用する言語を選択します。 コンソールコードエディタは Node.js、Python、および Ruby のみをサポートします。 実行ロール 関数のアクセス権限を定義するロールを選択します。以下の3つから選択可能です。 ・基本的な Lambda アクセス権限で新しいロールを作成 ・既存のロールを使用する ・AWS ポリシーテンプレートから新しいロールを作成 説明 関数の説明を入力することができます。 メモリ 作成する関数には、設定したメモリに比例する CPU が割り当てられます。 メモリを 128 MB~10240 MB の間で設定します。 指定したメモリにより料金が変動します。デフォルトは128MBです。 タイムアウト 関数が停止するまでに許可される実行時間。 デフォルトは 3 秒です。 許容されている最大値は 900 秒 です。 トリガー トリガー設定を行うと別のサービス(API Gatewayなど)での、 イベントの発生をきっかけに処理を行うことができます。 送信先 呼び出しレコードを別のサービスに送信するように Lambda を設定することもできます。Lambda は、非同期呼び出しに対して以下の送信先をサポートしています。 ・Amazon SQS – 標準 SQS キュー。 ・Amazon SNS – SNS トピック。 ・AWS Lambda – Lambda 関数。 ・Amazon EventBridge – EventBridge イベントバス。 呼び出しレコードには、JSON 形式のリクエストとレスポンスに関する詳細が含まれます。 処理に成功したイベント用と、 すべての処理試行に失敗したイベント用に別々の送信先を設定できます。 環境変数 環境変数を使用すると、コードを更新せずに関数の動作を調整できます。 環境変数は、関数のバージョン固有の設定に保存される文字列のペアです。 タグ タグは、AWS リソースに割り当てるラベルです。 各タグは、キーとオプションの値で構成されます。 タグを使用して、リソースを検索およびフィルタリングしたり、 AWS コストを追跡したりできます。 同時実行 Lambdaを1秒間に同時実行することができる回数を指定します。 デフォルトは1000回になっています。 例えば、同時実行が100だとします。 3秒かかる処理を1秒ごとに50回実行したとすると、以下のようになります。 1秒目:同時実行数は、50回 2秒目:1秒目に実行された50回+2秒目から実行された50回 3秒目:1秒目に実行された50回+2秒目から実行された50回+3秒目からの50回 こと時、2秒目までは同時実行数100回でも足りますが、 3秒目には1秒間150回の要求が来ているため、エラーが返されます。 コード書名 コード署名を使用して、未検証コードのデプロイを制限します。 コード署名プロファイルを作成するには、次を参照してください。 イベントの最大有効期間(非同期処理) 未処理のイベントをキューに保持する最大時間。 再試行(非同期処理) 関数がエラーを返すときに再試行する最大回数。 デッドレターキューサービス(非同期処理) 非同期呼び出しから Amazon SQS キューまたは Amazon SNS トピックに未処理のイベントを送信できます。 さいごに 以上になります。 もう少し設定項目はありそうでしたが、 今回は考慮する必要がない設定項目だったので記載しておりません。。。 もし気が向いたら追記しておこうと思います。 いつかは、LambdaからDynamoDBにデータを書き込むまでの記事を作成したいな。 もしよかったらそちらもご覧ください。
- 投稿日:2021-08-27T16:38:06+09:00
Lambda関数内で、別AWSアカウントのLambda関数を呼び出す
AWSアカウントA内のLambda関数から、AWSアカウントB内にあるLambda関数を呼び出す方法の備忘録です。 もともとのゴールは、アカウントA内のAmazon Lexボットから、アカウントB内のLambda関数を直接呼び出すことでした。 しかし現状無理そうなので、アカウントA内の(プロキシ)Lambda関数を経由して、間接的にアカウントBの(本命)Lambda関数を呼び出すことにしました。 概要 Lexボットがある、呼び出し側のAWSアカウントをアカウントA(ID:999999999999)、呼び出される本命Lambda関数がある側のAWSアカウントをアカウントB(ID:000000000000)とします。 アカウントA内に作成するプロキシLambda関数が、アカウントB内の本命Lambda関数を呼び出すには、アカウントBの側でアカウントAのアクセスを許可する必要があります。 セットアップ全体の流れは次のとおり。 アカウントB内に、本命Lambdaの実行権限を持つIAM Roleを作成 アカウントA内に、上記のRoleと連携するRoleを作成 アカウントA内で、このRoleの下にプロキシLambda関数を作成 プロキシLambda内で、Roleの権限を行使して本命Lambdaを実行 (おまけ)LexボットがプロキシLambda関数を呼び出すようにする Step 1:アカウントB内に IAM Roleを作成 まずアカウントB側で、本命Lambdaを実行できる権限を持つ、アカウントA用のIAM Roleを作成します。 アカウントB(ID:000000000000、本命Lambda側)上で、AWS管理コンソールのメニューから IAM > Access management > Rolesを開きCreate roleボタンをクリック。 Select type of trusted entityセクションでAnother AWS accountを選択し、Account ID欄にアカウントAのIDを入力。アカウントAがこのロールを担う主体となります。 Next: Permissionsをクリック。 Attach permissions policiesセクションでは、このロールが持つ権限としてAWSLambdaRoleポリシーを選択し、次に進みます。 Tagsセクションでは、必要であればタグを指定して次に進みます。 次のReviewセクションで、Role name欄に任意のロール名を入力して、Create roleボタンをクリック。 ロールが新規作成されます。 作成されたロールを開き、ロールのRole ARNを控えておきます。(Step 2と3で使用する) Step 2:アカウントA側にもロールを作成 次はアカウントA側に、Step 1で作成したロールと連携するロールを新規作成します。 アカウントA(ID:999999999999、LexボットとプロキシLambda側)上で、AWS管理コンソールのメニューから IAM > Access management > Roles を開き、Create roleボタンをクリック。 Select type of trusted entityセクションでAWS service、Choose a use caseセクションではLambdaを選択。 Attach permissions policiesセクションで、Create policyボタンをクリック。 新しいブラウザーウィンドウ(またはタブ)が開きます。JSONタブに移動し、下記のようなインラインポリシーを作成します。 インラインポリシーのテキストはこちら↓。 Resourceの値として、Step 1で作成したロールのARNを指定します。 AssumeRolePolicy { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam::000000000000:role/myIntegrationLambda" //アカウントBで作成したロールのARN } ] } Tagsセクションは、必要であればタグを指定して次に進みます。 次のReview policyセクションで、Name欄に任意のポリシー名を入力し、Create policyボタンをクリック。 インラインポリシーが新規作成されます。 このウィンドウ(またはタブ)を閉じて、手続き途中だったCreate roleのウィンドウに戻ります。 Create roleのブラウザーウィンドウに戻り、Attach permissions policiesセクションで、ロールに付与するポリシーを選択します。 ここではAWSLambdaBasicExecutionRoleと、今作成したインラインポリシーを選択。 AWSLambdaBasicExecutionRoleはアカウントA内のLambdaを実行する権限、インラインポリシーはStep 1で作成した、アカウントB側のロールを執行する権限を付与するポリシーです。 Next: Tagsボタンをクリック。 Tagsセクションでは、必要であればタグを指定して、次に進みます。 次のReviewセクションで、Role name欄に任意のロール名を入力してCreate roleボタンをクリック。 アカウントA側のロールが新規作成されます。 Step 3:アカウントA側で(アカウントB内の本命Lambdaを呼び出す)プロキシLambdaを作成 アカウントA(ID:999999999999)のAWS管理コンソールで、Lambdaを開き、Create functionボタンをクリック。プロキシLambda関数を新規作成します。 Author from scratchを選び、Function name 欄に任意の関数名を入力。 RuntimeはNode.js 14.xを選択し、Change default execution roleセクションをクリックして開く。 Change default execution roleセクションでは、Step 2で作成したロールを指定するのでUse an existing roleを選択します。 Existing roleのドロップダウンリストで、Step 2で作成したロールを選びます。 このロール選択により、プロキシLambdaがアカウントBの本命Lambdaを実行できる権限を持ちます。 Create functionボタンをクリックして、Lambda関数を新規作成します。 Step 4:プロキシLambda内で、Roleの権限を行使して本命Lambdaを実行 本命Lambda関数を呼び出して実行するプロキシLambda関数のコードを書きます。 Lambda関数の画面では、上部右側に、その関数のARNが表示されています。プロキシLambdaのコード内で、本命LambdaのARNが必要になるので、予めアカウントB内の本命Lambdaから取得しておきます。 index.jsに、下記のコードを入力します。 ProxyLambda const aws = require('aws-sdk'); "use strict"; // --------------- Main handler ----------------------- // Route the incoming request based on intent. // The JSON body of the request is provided in the event slot. exports.handler = async (event, context, callback) => { console.log("Started"); const lexPost = JSON.stringify(event); console.log(lexPost); var sts = new aws.STS({apiVersion: '2011-06-15'}); var stsParams = { RoleArn: "arn:aws:iam::000000000000:role/myIntegrationLambda", //Step 1で作成したロールのARN DurationSeconds: 3600, RoleSessionName: "assumeRoleSession" }; const stsResults = await sts.assumeRole(stsParams).promise(); console.log("STS Result: ", stsResults); var lambda = new aws.Lambda({ region: 'ap-northeast-1', //アカウントAのlambdaがあるリージョン accessKeyId: stsResults.Credentials.AccessKeyId, secretAccessKey:stsResults.Credentials.SecretAccessKey, sessionToken: stsResults.Credentials.SessionToken }); console.log("Got new Lambda"); const params = { FunctionName: "arn:aws:lambda:ap-northeast-1:000000000000:function:myMainLambda", //アカウントAのlambdaのARN InvocationType: "RequestResponse", Payload: JSON.stringify(event) }; console.log("Params: ", params); const res = await lambda.invoke(params, (err, data) => { let res = data; if (err) { console.log("呼び出し失敗"); console.log(err); callback(err, err); } else { console.log("呼び出し成功"); console.log("response:", res); callback(null, JSON.parse(res.Payload)); } }).promise(); }; 18行目のRoleArnには、Step 1の最後で控えたARNを指定します。 37行目のFunctionNameには、アカウントBにある本命lambda関数のARNを指定します。 Deployボタンでコードをデプロイします。 Step 5:(おまけ)LexボットがプロキシLambda関数を呼び出すようにする LexボットのインテントがプロキシLambda関数実行できるよう、FulfillmentセクションでStep 3、4のプロキシLambda関数を指定します。 まず、Step 4の最後でコードをデプロイしたあと、Versionsタブに移動します。 Publish new versionボタンをクリックして新しいバージョンを作成します。 バージョンを発行することで、LexボットがIntentのFulfillmentにこのlambda関数を利用できるようになります。 アカウントA上で、AWS管理コンソールのメニューからAmazon Lexをクリックして移動し、Lambda関数を実行させたいIntentを開きます。 IntentのFulfillmentセクションで、プロキシLambda関数を指定し、Intentを保存します。
- 投稿日:2021-08-27T16:26:48+09:00
Amazon Lex の V1 Bot を V2 Bot に移行する
はじめに 2021/7/14 に Amazon Lex の V1 API で作成されたチャットボットを V2 に移行できる Migration Tool が利用可能になりました。 V2 API がリリースされた当初は手動の移行 (実質再作成) が必要だったのですが、これにより主要な設定を V2 API のボットとして移行できるようになりました。 Lex V1 と V2 の違い Amazon Lex は 2021年1月に V2 API がリリースされています。コンソールのデザインが変わっただけではなく、新しい機能を含む新規の API としてのリリースです。1 つのボットで複数言語に対応させることができるなど、生産性が向上するアップデートも多く含まれています。 Migration Tool で移行されるもの カスタムインテントとスロットタイプのみが V2 Bot に移行されます V2 Bot では 1 つのボットで複数言語に対応できるため、異なる言語で作成された複数の V1 Bot を 1 つの V2 Bot に移行することもできます 以下の設定は移行対象外です。 ボットのエイリアス Amazon Kendra インデックス AWS Lambda関数 会話ログの設定 メッセージングチャネルの連携 (Slack など) Tag Lex の応答で Lambda 関数を使用している場合は手動で移行する必要がありますが、そもそも V2 API の Input event format と Response format に合わせて Lambda 関数を改修する必要があるので致し方ないかと思います。(V1 用の Lambda 関数はそのままでは動かない) V2 API のフォーマットは以下のドキュメントをご確認ください。 やってみる 移行作業 Lex のコンソールで提供されているサンプルの BookTrip を移行してみます。 V1 コンソールの Migration Tool から対象のボットを選択し、Migrate をクリックします。 Step 1 で移行元の Bot version と選択し、移行先の V2 Bot の名前を入力して次に進みます。 Step 2 で移行先の V2 Bot に設定する IAM ロールを新規作成するか、既存の IAM ロールを指定します。 Step 3 では設定内容を確認して、Start migration をクリックするだけです。簡単ですね! 移行結果の確認 Migration Tool の画面下部、History から移行結果を確認することができます。Migration status が IN_PROGRESS から COMPLETED になるまで少し待機します。完了後、Migaration details の View から移行結果を確認することができます。 V2 Bot に移行できないリソースがあった場合は、Alerts として表示されます。ドキュメントのリンクから対応方法を確認できます。以下の例では Hang-up phrases が V2 Bot ではサポートされないためにアラートメッセージが表示されています。V2 Bot は一致するインテントがなかった場合に呼び出される FallbackIntent がデフォルトで設定されるため、大きな問題にはならないかと思います。 V2 コンソールを確認すると、カスタムインテントとスロットタイプが移行されていることを確認できます。 複数言語の統合 先ほどは BookTrip の日本語ボットを V2 Bot に移行しましたが、V2 Bot に言語を追加する形で V1 の英語ボットを移行してみます。 BookTrip の英語ボットを選択し、Migrate をクリックします。 Step1 で 移行先の V2 Bot 名に先ほどと同じボット名を入力すると、Step 2 で以下のような警告メッセージが表示されます。移行先の English (US) のドラフトバージョンの設定が存在する場合は上書きされるという内容ですが、今回は新たに英語の言語設定を追加することが目的ですので問題ありません。 完了後、V2 コンソールで移行先のボットを確認すると、言語に英語が追加されていることを確認できます。 参考 簡単ですが以上です。 参考になれば幸いです。
- 投稿日:2021-08-27T11:59:26+09:00
EC2に自動でEIPを割り当ててくれるシェルスクリプト
概要 普段、Terraformを使用している私にとって、EC2を起動した際などに使用するEIPは ドメインを割り振る関係上、簡単に変更できないように Terraformのライフサイクルに含めたくないケースが多い。 そんなときに便利な EIPを作成し、EC2へそのEIPを自動で割り当ててくれるシェルスクリプトを紹介する。 動作環境 Linux Debian [v10.8] Windows WSL の Ubuntu [v20.04] WSLの構築については以下を参照 シェルスクリプト #!/bin/bash set -eu create_and_set_eip () { # サーバ用Elastic IP作成 and EC2連携 aws ec2 allocate-address --domain vpc --tag-specifications "ResourceType=elastic-ip,Tags=[{Key=Name,Value=${AWS_PROFILE}}]" aws ec2 associate-address \ --allocation-id `aws ec2 describe-addresses --filter "Name=tag:Name,Values=${AWS_PROFILE}" --query 'Addresses[*].AllocationId[]' --output text` \ --instance `aws ec2 describe-instances --filter "Name=tag:Name,Values=${AWS_PROFILE}" "Name=instance-state-name,Values=running" --query 'Reservations[*].Instances[*].InstanceId[]' --output text` } # [source set_aws_profile.sh] を実行し、デプロイ先を指定しているか確認 if [ ${AWS_PROFILE} = '******(アプリ名など)' ]; then create_and_set_eip echo '----- Elastic IP作成 and EC2連携完了 -----' else echo '[source set_aws_profile.sh] を実行し、デプロイ先を指定して下さい。' fi 説明 1. 事前準備 AWS CLI のインストール AWSのクレデンシャル情報などを保存する、名前付きプロファイルの名前を EC2のNAMEタグと一致させるようにする。(以下コマンドで設定するやつ) aws configure --profile ******(アプリ名など) 上記の名前付きプロファイルの名前を環境変数(AWS_PROFILE)に設定しておく export AWS_PROFILE=******(アプリ名など) 2. ポイント解説 1. 事前準備 で設定したように、名前付きプロファイルの名前を EC2のNAMEタグと一致させるようにすることで、デプロイ先が変わっても 上記シェルスクリプトをそのまま流用することができる 間違って操作するとヤバいことになるEIPの操作を自動化できる 以前紹介した、私のTerraform運用オペレーションに組み込むことができる 参考 AWS CLIのフィルターとクエリーの使い方についてまとめてみた
- 投稿日:2021-08-27T11:21:05+09:00
AWSのEC2インスタンスでAmazon Correttoを用いてJDK16を導入する
とあるサーバー向けソフトウェアでJava16を必要とする事があった。 すでにAmazon Corretto 8を用いてJDK8がインストールされていたが、 AmazonLinuxならAmazon CorrettoというOpenJDK互換のソフトウェアが簡単にインストールとバージョン切り替えが可能なのでその方法を説明する。 この記事ではAmazon Corretto 16のインストールについて解説するが、Corretto 8については次の記事を参考にしてほしい。→AWSのEC2インスタンスでAmazon Correttoを用いてJDK8を導入する 環境 AWS EC2 t4g.medium ARM AmazonLinux2 JDK 1.8.0_302 がインストール済み 今回はARM版のAmazonLinux2を利用しているが、x86でも手順はほぼ同様だと思われる。 インストール 今回はyumからインストールを行う。rpmからマニュアルでインストールする方法はこちら→AWSのマニュアル Amazon Linux2でyumリポジトリを有効にする。 AWSが用意したAmazon Corretto用のリポジトリの公開鍵をインポートし、リポジトリをシステムに追加する。 sudo rpm --import https://yum.corretto.aws/corretto.key sudo curl -L -o /etc/yum.repos.d/corretto.repo https://yum.corretto.aws/corretto.repo リポジトリの追加後、以下コマンドでインストールを行う。 sudo yum install -y java-16-amazon-corretto-devel Amazon Corretto 8の場合と比較すると今回インストールするのはJDKだと予測できるが、公式ドキュメントにCorretto 16でのJDK,JREについての記載はなくJDKのリンクのみが記載されていた。 Amazon Corretto 16は/usr/lib/jvm/java-16-amazon-correttoにインストールされる。 Corretto 8の場合と異なり、ディレクトリ名にCPUアーキテクチャーの記載が無いが、yumのログを見ると Downloading packages: java-16-amazon-corretto-devel-16.0.2.7-1.aarch64.rpm | 197 MB 00:00:08 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : 1:java-16-amazon-corretto-devel-16.0.2.7-1.aarch64 1/1 Verifying : 1:java-16-amazon-corretto-devel-16.0.2.7-1.aarch64 1/1 となっているのでアーキテクチャーに応じたソフトウェアが適宜インストールされているようだ。 バージョンの切り替え 環境によってはすでにJavaが入っており、java --versionで旧バージョンが有効になってしまうことがある。 java -version openjdk version "1.8.0_302" OpenJDK Runtime Environment Corretto-8.302.08.1 (build 1.8.0_302-b08) OpenJDK 64-Bit Server VM Corretto-8.302.08.1 (build 25.302-b08, mixed mode) これは以下コマンドを利用してJavaの切り替えを行い対応する。 sudo alternatives --config java There are 2 programs which provide 'java'. Selection Command ----------------------------------------------- + 1 /usr/lib/jvm/java-1.8.0-amazon-corretto.aarch64/jre/bin/java * 2 /usr/lib/jvm/java-16-amazon-corretto/bin/java Enter to keep the current selection[+], or type selection number: 2 変更を確認する。 java -version openjdk version "16.0.2" 2021-07-20 OpenJDK Runtime Environment Corretto-16.0.2.7.1 (build 16.0.2+7) OpenJDK 64-Bit Server VM Corretto-16.0.2.7.1 (build 16.0.2+7, mixed mode, sharing) 変更が確認できた。 なお、JDKを使用している場合は以下コマンドも合わせて実行する必要がある場合がある。 sudo alternatives --config javac 参考記事 公式のAmazon Corretto 16インストール記事 https://docs.aws.amazon.com/corretto/latest/corretto-16-ug/generic-linux-install.html#rpm-linux-install-instruct 私が過去に執筆したAmazon Corretto 8についてのQiitaの記事 https://qiita.com/honahuku/items/e5464bb3b102710b555a
- 投稿日:2021-08-27T11:13:29+09:00
Terraform+SAMでLambda+APIGatewayの環境構築
どういう記事か terraform, samの初心者がapi gateway + lambda + cloudfrontの環境構築をしたときのメモです。 前提 m1 mac macos big sur 参考 terraformのダウンロード&インストール tfenvから導入を始めます。 tfenvが正しい方法なのかはよくわかっていませんが、、 brew install tfenv 今回は 0.15.5をインストールしてみました。 tfenv install 1.0.5 Installation of terraform v1.0.5 successful. To make this your default version, run 'tfenv use 1.0.5' これで設定します。 $ tfenv use 1.0.5 $ terraform --version Terraform v1.0.5 on darwin_amd64 aws samのダウンロードとインストール homebrewでインストールしようとするとpermission deniedエラーが出てきて解決できなかったのでpipで解決しました。 $ pip install aws-sam-cli $ sam --version SAM CLI, version 1.29.0 terraform初期化 terraform initでプロジェクトをスタートします。 terraform init Initializing the backend... Initializing provider plugins... - Finding hashicorp/aws versions matching "~> 3.0"... - Installing hashicorp/aws v3.56.0... - Installed hashicorp/aws v3.56.0 (signed by HashiCorp) Terraform has created a lock file .terraform.lock.hcl to record the provider selections it made above. Include this file in your version control repository so that Terraform can guarantee to make the same selections by default when you run "terraform init" in the future. Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary. samの初期化 python 3.9で作成しました。photo-stackというフォルダが作成されます。 $ sam init SAM CLI now collects telemetry to better understand customer needs. You can OPT OUT and disable telemetry collection by setting the environment variable SAM_CLI_TELEMETRY=0 in your shell. Thanks for your help! Learn More: https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-telemetry.html Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Choice: 1 What package type would you like to use? 1 - Zip (artifact is a zip uploaded to S3) 2 - Image (artifact is an image uploaded to an ECR image repository) Package type: 1 Which runtime would you like to use? 1 - nodejs14.x 2 - python3.9 3 - ruby2.7 4 - go1.x 5 - java11 6 - dotnetcore3.1 7 - nodejs12.x 8 - nodejs10.x 9 - python3.8 10 - python3.7 11 - python3.6 12 - python2.7 13 - ruby2.5 14 - java8.al2 15 - java8 16 - dotnetcore2.1 Runtime: 2 Project name [sam-app]: photo-stack Cloning from https://github.com/aws/aws-sam-cli-app-templates AWS quick start application templates: 1 - Hello World Example 2 - EventBridge Hello World 3 - EventBridge App from scratch (100+ Event Schemas) 4 - Step Functions Sample App (Stock Trader) 5 - Elastic File System Sample App Template selection: 1 ----------------------- Generating application: ----------------------- Name: photo-stack Runtime: python3.9 Dependency Manager: pip Application Template: hello-world Output Directory: . Next steps can be found in the README file at ./photo-stack/README.md pythonのバージョンをpipenvで調整 pipenvを使ってpython 3.9を使うようにしました。 $ pipenv --python 3.9 Warning: the environment variable LANG is not set! We recommend setting this in ~/.profile (or equivalent) for proper expected behavior. Creating a virtualenv for this project... Pipfile: /xxxxxx Using /usr/local/bin/python3.9 (3.9.6) to create virtualenv... ⠼ Creating virtual environment...created virtual environment CPython3.9.6.final.0-64 in 220ms creator CPython3Posix(dest=/Users/xxxxx/.local/share/virtualenvs/photo-stack-ZfxSBrfk, clear=False, no_vcs_ignore=False, global=False) seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=/Users/xxxxxx/Library/Application Support/virtualenv) added seed packages: pip==21.1.2, setuptools==57.0.0, wheel==0.36.2 activators BashActivator,CShellActivator,FishActivator,PowerShellActivator,PythonActivator,XonshActivator ✔ Successfully created virtual environment! Virtualenv location: /Users/xxxxxxxx/.local/share/virtualenvs/photo-stack-ZfxSBrfk Creating a Pipfile for this project... バケットの作成 以下のコマンドでバケットを作成します。 $ aws s3api create-bucket --bucket photo-stack --region ap-northeast-1 --acl private --create-bucket-configu ration LocationConstraint=ap-northeast-1 sam/template.ymlの修正 APIのドメインをアウトプットとして出すようにします。 Outputs: # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function # Find out more about other implicit resources you can reference within SAM # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api HelloWorldApiDomain: Value: !Sub "${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com" その他terraformファイルの作成 cloudformationの設定です。 【注意】こちらの3行目のtemplate.ymlはsam/template.ymlではなく、terraformによって生成されるtemplate.ymlのことです。 cloudformation.tf resource "aws_cloudformation_stack" "sam" { name = "sam" template_body = file("template.yaml") capabilities = ["CAPABILITY_IAM", "CAPABILITY_AUTO_EXPAND"] } data "aws_cloudformation_stack" "sam" { name = "sam" depends_on = [ aws_cloudformation_stack.sam ] } cloudfrontの設定: cloudfront.tf resource "aws_cloudfront_distribution" "api_dist" { origin { domain_name = data.aws_cloudformation_stack.sam.outputs["HelloWorldApiDomain"] origin_id = "sam-api-gateway" custom_origin_config { https_port = 443 http_port = 80 origin_protocol_policy = "https-only" origin_ssl_protocols = ["TLSv1.2"] } } enabled = true default_cache_behavior { allowed_methods = [ "GET", "HEAD" ] cached_methods = ["GET", "HEAD"] target_origin_id = "sam-api-gateway" forwarded_values { query_string = false cookies { forward = "none" } } viewer_protocol_policy = "https-only" min_ttl = 0 default_ttl = 3600 max_ttl = 86400 } restrictions { geo_restriction { restriction_type = "whitelist" locations = [ "JP" ] } } viewer_certificate { cloudfront_default_certificate = true } } deploy用のMakefileを作成しました。 PROFILE=default SAM_APP_DIR=photo-stack SAM_BUCKET=photo-stack TEMPLATE_FILE=template.yaml deploy: cd $(SAM_APP_DIR) && pipenv run sam build cd $(SAM_APP_DIR) && sam package --profile $(PROFILE) --s3-bucket $(SAM_BUCKET) --output-template-file ../$(TEMPLATE_FILE) terraform apply deployする make deployすると以下のような感じでデプロイが進んで終了します。 $ make deploy cd photo-stack && pipenv run sam build Building codeuri: /Users/xxxxxxxxx/Documents/zeroboard-C-photo-editor/photo-stack/hello_world runtime: python3.9 metadata: {} functions: ['HelloWorldFunction'] Running PythonPipBuilder:ResolveDependencies Running PythonPipBuilder:CopySource Build Succeeded Built Artifacts : .aws-sam/build Built Template : .aws-sam/build/template.yaml Commands you can use next ========================= [*] Invoke Function: sam local invoke [*] Deploy: sam deploy --guided cd photo-stack && sam package --profile default --s3-bucket photo-stack --output-template-file ../template.yaml File with same data already exists at 88bd6722efd39f95c2a8ca00aad6e623, skipping upload Successfully packaged artifacts and wrote output template to file ../template.yaml. Execute the following command to deploy the packaged template sam deploy --template-file /Users/xxxxxxx/Documents/zeroboard-C-photo-editor/template.yaml --stack-name <YOUR STACK NAME> terraform apply Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create <= read (data resources) Terraform will perform the following actions: ====== 略 ====== Do you want to perform these actions? Terraform will perform the actions described above. Only 'yes' will be accepted to approve. Enter a value: yes aws_cloudformation_stack.sam: Creating... aws_cloudformation_stack.sam: Still creating... [10s elapsed] aws_cloudformation_stack.sam: Still creating... [20s elapsed] aws_cloudformation_stack.sam: Still creating... [30s elapsed] aws_cloudformation_stack.sam: Still creating... [40s elapsed] aws_cloudformation_stack.sam: Still creating... [50s elapsed] aws_cloudformation_stack.sam: Still creating... [1m0s elapsed] aws_cloudformation_stack.sam: Creation complete after 1m8s [id=arn:aws:cloudformation:ap-northeast-1:803801015105:stack/sam/528f5330-06d8-11ec-adb9-0adad91fe6c5] data.aws_cloudformation_stack.sam: Reading... data.aws_cloudformation_stack.sam: Read complete after 1s [id=arn:aws:cloudformation:ap-northeast-1:803801015105:stack/sam/528f5330-06d8-11ec-adb9-0adad91fe6c5] aws_cloudfront_distribution.api_dist: Creating... aws_cloudfront_distribution.api_dist: Still creating... [10s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [20s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [30s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [40s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [50s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [1m0s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [1m10s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [1m20s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [1m30s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [1m40s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [1m50s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [2m0s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [2m10s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [2m20s elapsed] aws_cloudfront_distribution.api_dist: Still creating... [2m30s elapsed] aws_cloudfront_distribution.api_dist: Creation complete after 2m38s [id=E3AH96C5XZK11E] Apply complete! Resources: 2 added, 0 changed, 0 destroyed. 動作確認 hello worldというメッセージが返ってきたらOKです。 $ curl https://xxxxxxx.cloudfront.net/Prod/hello {"message": "hello world"}% 消去 バケットを消去して、以下のコマンドでできます。 $ terraform destroy aws_cloudformation_stack.sam: Refreshing state... [id=arn:aws:cloudformation:ap-northeast-1:803801015105:stack/sam/528f5330-06d8-11ec-adb9-0adad91fe6c5] aws_cloudfront_distribution.api_dist: Refreshing state... [id=E3AH96C5XZK11E] Note: Objects have changed outside of Terraform ===== 略 ===== Do you really want to destroy all resources? Terraform will destroy all your managed infrastructure, as shown above. There is no undo. Only 'yes' will be accepted to confirm. Enter a value: yes aws_cloudfront_distribution.api_dist: Destroying... [id=E3AH96C5XZK11E] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 10s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 20s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 30s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 40s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 50s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 1m0s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 1m10s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 1m20s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 1m30s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 1m40s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 1m50s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 2m0s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 2m10s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 2m20s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 2m30s elapsed] aws_cloudfront_distribution.api_dist: Still destroying... [id=E3AH96C5XZK11E, 2m40s elapsed] aws_cloudfront_distribution.api_dist: Destruction complete after 2m41s aws_cloudformation_stack.sam: Destroying... [id=arn:aws:cloudformation:ap-northeast-1:803801015105:stack/sam/528f5330-06d8-11ec-adb9-0adad91fe6c5] aws_cloudformation_stack.sam: Still destroying... [id=arn:aws:cloudformation:ap-northeast-1:8...m/528f5330-06d8-11ec-adb9-0adad91fe6c5, 10s elapsed] aws_cloudformation_stack.sam: Still destroying... [id=arn:aws:cloudformation:ap-northeast-1:8...m/528f5330-06d8-11ec-adb9-0adad91fe6c5, 20s elapsed] aws_cloudformation_stack.sam: Still destroying... [id=arn:aws:cloudformation:ap-northeast-1:8...m/528f5330-06d8-11ec-adb9-0adad91fe6c5, 30s elapsed] aws_cloudformation_stack.sam: Destruction complete after 37s Destroy complete! Resources: 2 destroyed.
- 投稿日:2021-08-27T10:43:26+09:00
AWSのEC2インスタンスでAmazon Correttoを用いてJDK8を導入する
とあるサーバー向けソフトウェアでJava16を必要とする事があった。 AmazonLinuxならAmazon CorrettoというOpenJDK互換のソフトウェアが簡単にインストールとバージョン切り替えが可能なのでその方法を説明する。 この記事ではAmazon Corretto 8のインストールについて解説するが、Corretto 16については次の記事を参考にしてほしい。→AWSのEC2インスタンスでAmazon Correttoを用いてJDK16を導入する 環境 AWS EC2 t4g.medium ARM AmazonLinux2 Javaは未インストール 今回はARM版のAL2を利用しているが、x86でも手順はほぼ同様だと思われる。 インストール 今回はyumからインストールを行う。rpmからマニュアルでインストールする方法はこちら→AWSのマニュアル Amazon Linux2でyumリポジトリを有効にする。 sudo amazon-linux-extras enable corretto8 Amazon Corretto 8は、ランタイム環境(JRE)及び完全開発環境(JDK)の2種類が用意されている。 なお、JDKにはJREが含まれるのでJDKをインストールするならばJREをインストールする必要はない。 Amazon Corretto 8をJREとしてインストールする場合 sudo yum install java-1.8.0-amazon-corretto Amazon Corretto 8をJDKとしてインストールする場合 sudo yum install java-1.8.0-amazon-corretto-devel Amazon Corretto 8は/usr/lib/jvm/java-1.8.0-amazon-corretto.<cpu_arch>にインストールされる。 バージョンの切り替え 環境によってはすでにJavaが入っており、java --versionで旧バージョンが有効になってしまうことがある。 java -version openjdk version "1.8.0_302" OpenJDK Runtime Environment Corretto-8.302.08.1 (build 1.8.0_302-b08) OpenJDK 64-Bit Server VM Corretto-8.302.08.1 (build 25.302-b08, mixed mode) これは以下コマンドを利用してJavaの切り替えを行い対応する。 sudo alternatives --config java There are 2 programs which provide 'java'. Selection Command ----------------------------------------------- + 1 /usr/lib/jvm/java-1.8.0-amazon-corretto.aarch64/jre/bin/java * 2 /usr/lib/jvm/java-16-amazon-corretto/bin/java Enter to keep the current selection[+], or type selection number: 2 変更を確認する。 java -version openjdk version "16.0.2" 2021-07-20 OpenJDK Runtime Environment Corretto-16.0.2.7.1 (build 16.0.2+7) OpenJDK 64-Bit Server VM Corretto-16.0.2.7.1 (build 16.0.2+7, mixed mode, sharing) 変更が確認できた。 なお、JDKを使用している場合は以下コマンドも合わせて実行する必要がある場合がある。 sudo alternatives --config javac 参考記事
- 投稿日:2021-08-27T10:09:08+09:00
【プログラミング初学者�・AWS初学者必見!!】なぜS3を使うのか
はじめに 自己紹介 初めまして、バックエンドエンジニアを目指して転職活動中の小林 凌(こばやし りょう)と申します。 今回は、AWS(EC2/S3)について勉強しましたので、アウトプットしていきたいと思います! 記事の対象者 プログラミング初学者 これからAWSの勉強を始める方 EC2について勉強した人 S3について勉強したい人 メインはプログラミング初学者となります。 なので極力専門的なワードを使用せず、具体例を交えて記事を作成しています。 記事作成の背景 作成したポートフォリオに画像投稿機能を追加したかったので、調べたところ、AWSでデプロイするならば、S3というストレージサービスを使った方が良いということがわかりました。しかし、この時点で中途半端についていた知識が邪魔します。 「EC2にもストレージサービスあんだからそれ使えばいいんじゃね?」 「なんでS3なの?」 っていうところからです、黙ってS3使えばいいのに、、、 発言からわかる通り、あんまり賢くないです。ってかばk、、、 記事の構成 これ以降のざっくりした記事構成と概要です。 目次 概要 EC2の役割 EC2の基本的な部分について説明しています。 S3の役割 S3の基本的な部分について説明しています。 具体例:S3を活用したアプリケーション 画像投稿機能が実装されたアプリケーションの挙動やメリットについて説明しています。 具体例:EC2を活用したアプリケーション 上記同様ですが、ここではデメリットのみ説明しています まとめ まとめです 疑問を解決してくれたサービス、参考書籍 書籍、サービスの紹介 EC2の役割 EC2とは 一言で言えば、webサービス等における心臓です!(サーバーに必要なものを一式クラウドで借りられる) バックエンドエンジニアやフロントエンドエンジニアが作り上げたアプリケーションを立ち上げる場所になります。 当然ですが、ここがダメージを受けると、webサービスは停止してしまいます。 なので、インフラエンジニアの皆様方は、そうならないようEC2に負担をかけない設計をしてくれています。 EC2の主要な機能 EC2インスタンス EC2インスタンスとは、AWSクラウド上に作られた仮想サーバー(サービスを提供する場所)のことです。 インスタンスと呼ばれる所以としては、次項で説明するAMIを活用して同じ構成のサーバーを何個も作れるからです。 ちなみにEC2とは、AWSが提供するサービス名であって、正式名称はAmazon EC2となります。 AMI よく例えられるたい焼きの話と一緒です。要は、AMIとはたい焼きを作る型です。これにたい焼きのもとを流し込むことで、EC2インスタンスが作成されるのです。 EBS EBSとはEC2インスタンス専用のストレージサービスです。テレビの外付けハードディスク的な存在です。確保容量があらかじめ決まっています。 ElasticIP 固定IPアドレスです。EC2インスタンスは停止後に再起動をかけるとグローバルIPアドレスが変わってしまい、以前のグローバルIPアドレスではアクセスできなくなります。要はサイトやサービスにアクセスができなくなるということです。 それでは困るので、この機能により、固定のIPアドレスを付与できるのです。 ElasticIPは直接EC2インスタンスにアクセスする場合のみ使用します。後述するELBを使用する場合は、ElasticIPを使用することはありません。 ELB サーバーにアクセスが集中した場合や、CPU使用率等により自動で複数のサーバーに負荷を振り分けてくれます。後述でも触れていますので、詳しくはそちらで。 WebサービスにおけるEC2 先ほど説明したEC2についてまとめるとこんな感じになります。 追加した部分についての簡単な説明を以下にまとめました。 Availability Zone => データセンターのこと。東京に4つ、大阪に3つ存在しており、ここにVPCを設置します。ap-northeast-1が東京リージョンを表し、a,c,dがそれぞれのデータセンターになります。bも存在しますが、説明は割愛します。先ほどの3つが使用できると考えてください。 public subnet => インターネットと接続できる。 private subnet => インターネットと接続できない。 RDS => マネージド型データベースサービス(MySQLやPostgreSQL) 見ての通り、EC2インスタンスが二つあります。先ほど心臓と例えましたが、人間と違い、Webサービスは複数の心臓を持つことができます。ちなみに世にあるサービス(AWSを使用した)でEC2インスタンス一個で運用しているサービスはありません。理由としては、サーバーにアクセスが集中し、万が一ダウンしてしまった場合に、EC2インスタンスが一個しかなければ、そのWebサービスは完全にストップしてしまうからです。 だから、EC2インスタンスは複数用意しなければならないのです。ちなみにこのような対策をとることを冗長化といいます。 また、EC2インスタンスが複数あれば、先ほど説明したELBを使って、負荷を分散することもできます。 S3の役割 S3とは 高機能なストレージサービスになります。例えるならば、ドラえもんの四次元ポケットみたいなものです。S3にも色々機能はありますが、今回は、メリットに注目したいと思います。次項の具体例で詳しく触れていきます。 具体例:S3を活用した画像投稿機能付きアプリケーション 今回はrailsで画像投稿機能を実装したアプリケーションをEC2インスタンスに立ち上げたと仮定し、構成は下記のようにしました。 ちなみに画像の保存先はgem "fog-aws"を利用し、S3に保存できるように設定しているとします。 構成 メリット Webサイトホスティング機能 これが最も便利な機能と言っても過言ではありません。この機能では、静的ファイルを「CloudFlont」(説明は割愛します)経由で公開することができます。静的ファイルとは、画像や動画、また画像とHTMLだけで作られているファイル等を指します。上の構成図(緑枠線内)を見てわかる通り、CloudFlont経由であれば、EC2にアクセスする必要がなく、EC2の負担がかかりません。 前述したようにEC2インスタンスが止まれば、サービスへの影響は甚大です。その意味でもこの機能はWebサービスを支える重要な機能と言えます。 容量が無制限 EC2のストレージであるEBSはあらかじめ容量が定められていますが、S3は容量が無制限です。 可用性、耐久性 障害やエラー等に対して強い。また最低3つのAvailability Zoneで自動で保存されているため、どこか一つのAvailability Zoneに障害があっても、使い続けることができる。 他にもたくさんありますが、とりあえずこの辺で。 ここまででも、十分にS3を使った方がいい理由やメリットがわかったと思います! では、S3を使わないWebサービスの場合を見ていきましょう。 具体例:S3を活用しない画像投稿機能付きアプリケーション 今回はデメリットだけに注目したいので、あえてインフラ構成も最低限のもので揃えました。 未経験からエンジニア転職を目指して、ポートフォリオを作り、AWSでデプロイする場合や個人開発の場合であれば、インフラ構成はこれでも足りると思います。 想定しているアプリケーションは上記同様で、違いは、下記の通りです。 冗長化措置が取られていない S3を使用していない 構成 デメリット デメリットは色々ありますが、今回はEBSの確保容量を超えた場合の挙動について注目したいと思います。 LinuxOSに影響が出る OSに影響が出ることで最も怖いのは、ログが出力されなくなることです。ログが出力されなければ、どんなに優秀なエンジニアであっても解決には時間がかかります。なぜなら、そのサービスに関連する全てのフォルダ、ファイル等の全てに目を通さなければならないからです。エラーコードがあれば、それを手がかりに解決を測れますが、なければ、完全手探り状態でエラー解決しなければなりません。サービスが停止して、その後普及までに時間が掛かれば、お客さんは離れてしまいます。 状況によっては、Nginxが停止する 影響はEC2インスタンス以外にも及ぶということです。 仮に冗長化されていてもEBSは複数のEC2インスタンスで共有できない EC2インスタンスがダウンした場合に、一緒にEBSも使えなくなってしまいます。 最近、EBSも複数のEC2インスタンスで共有できる機能がリリースされましたが、元々、共有を前提としたサービスではないので、不安が残ります。 => ちなみにEC2インスタンスでは、EBS以外にもEFSというストレージ機能があります。この機能であれば、複数のEC2インスタンスで共有可能、容量も自動拡張してくれます。 しかし、それでもS3を指定するのは、EC2への負担を軽減してくれるからです。 結論 EC2インスタンスに頼った設計では、確保容量を超えた場合、ログが出力されなくなる等の致命的なリスクを抱えている。 ログが出力されないことは、Webサービスとして致命的です。そのリスクを抱えてまで、EC2インスタンスに頼った設計をする必要はないと考えます。 まとめ S3を使えば、EC2インスタンスへの負担を減らし、安全なサービス運用につながる AWSを使ってポートフォリオをデプロイしたことを機に勉強を始めましたが、本当によかったと思います。 せっかくインフラエンジニアの方が、安全にサービスを運用できるインフラを整えてくれても、アプリケーション自体がインフラを考慮したコード設計になっていなければ、インフラエンジニアの努力は水の泡となります。そういった意味でもバックエンドエンジニアがインフラ関連の基礎知識を持っていることは重要だと感じました。今後も勉強を継続したいと思います。 疑問を解決してくれたサービス、参考書籍 私は現在、くろかわこうへいさんが主催する「AWS CloudTech」にてAWSについて勉強しています。 AWSの基本的な部分については、全て網羅されていますし、何より説明が丁寧でわかりやすいです。 初心者にはおすすめできるサービスです。質問もしやすい環境です! そして本記事執筆に伴い、同サービス内において、私の質問に対して丁寧に説明をしていただいた、公式メンターのルビコン(@RubiconLink)さん!本当にありがとうございました!今後ともよろしくお願いいたします。 私がAWSの勉強を始めるにあたって、参考になった書籍もリンク貼っておきます。ネット関連の知識がなくても、読みやすかったです。本記事でも参考にしました。
- 投稿日:2021-08-27T08:48:01+09:00
【個人開発】地域の魅力を発信できるデジタルパンフレットサービス「Openパンフレット」を作った
はじめに デジタルパンフレット作成公開サービス Openパンフレット をリリースしました。 個人開発です。 バックエンドはだいたいAWSです。 Android未対応? バックエンドの技術者がフロントやらインフラやらアプリやら色んな所に手を出して作ったシステムになっています。 記事本文はZennで書いているのでこちらです。 宣伝 Android版の開発のためクラウドファンディング募集しています。 よかったら見て下さい。励みになります。
- 投稿日:2021-08-27T06:10:01+09:00
【実践!AWS Lambda】Javaで書いたLambdaの初回起動が遅い問題を解決する
概要 AWS Lambdaの開発において、必ず出てくる初回起動が遅い問題、、、 NodejsやPythonなどのスクリプト言語のLambdaであれば対策は比較的簡単なのですが、Javaなどのコンパイル型の言語の場合は難易度が上がります JavaのLambdaの初回起動にかかる時間を8秒→1秒に短縮することに成功したので、ここに備忘録を残します 目次 前提条件 設計要素の洗い出し コールドスタート対策 DBコネクション対策 クラスローディング対策 前提条件 ・ランタイムはJava 11を使用 ・以下のような構成とする ①API GatewayをトリガーにLambdaが起動 ②RDS Proxyを介してAuroraに接続 ③ClientにResponceを返す 設計要素の洗い出し 時間がかかっている要因を洗い出していく ▼ 実行時間を計測 まずはPostmanからAPIを叩いて初回起動に要する時間を計測 実行時間 1回目 7245ミリ秒 2回目 683ミリ秒 3回目 364ミリ秒 4回目 537ミリ秒 5回目 366ミリ秒 明らかに初回が遅いことが分かる ▼ コールドスタート問題 Lambdaの実行時間を短縮したい場合にはまず、コールドスタートの回避を図る必要がある コールドスタートとはどのような状態なのかを理解するために、どのような仕組みでLambdaが実行されているかを整理してみる Lambda実行時、裏側では以下のような処理が走っている ➀ 実行環境の作成(コンテナ立ち上げ) ↓ ➁ デプロイパッケージのロード ↓ ➂ デプロイパッケージの展開 ↓ ➃ ランタイム起動・初期化 ↓ ➄ 関数/メソッドの実行 ↓ 10分~30分くらい(どのタイミングでコンテナが破棄されるかは決まっていない) ↓ ➅ コンテナの破棄 この➀~➄の全てを実行するのが、いわゆるコールドスタート コンテナが破棄される前に再度実行すると、➀~➃を省けるウォームスタートとなる 初回起動がおそいのは、コールドスタートになっている為である ▼DBのConnection問題 今回の設計上、コールドスタートを回避できたとしても、DBとのConnectionが切れていればConnection作成に時間がかかってしまう DB処理をさせるLambdaの場合は、この罠にも引っかからないように設計する必要がある ▼クラスローディング問題 ここはかなりはまりがち、、、Javaのようなコンパイル型言語ならではの罠 JavaのLambdaの場合コンテナ起動後に、 JVM(Javaを実行する仮想マシン)がクラスローディングを行いながら処理が走る仕様となっている 起動と実行の2段構えで時間がかかることになる(JavaのLambdaが遅いといわれる原因) ちなみにJVMも同じコンテナで使いまわされるので、2回目以降はクラスローディング済みの為早くなる 回避するには、コンテナ起動と同時にクラスローディングを済ませておく必要がある ▼設計要素まとめ 設計要素は以下のようになる ①コールドスタートの回避 ②DBのConnection維持 ③クラスローディング対策 ここから一つずつ解決していく コールドスタート対策 コールドスタートを回避するには、主に以下の2つの手段がある 1. Amazon EventBridgeでスケジュール実行させる 2. Provisioned Concurrencyで事前プロビジョニングしておく それぞれ一長一短あるので、簡単に解説 「Amazon EventBridge」 メリット ・コンテナを起動→実行まで定期実行できる ・Lambdaの実行の料金しかかからない デメリット ・スケジュール実行の合間にコンテナが破棄される可能性が否定できない(五分間隔でも稀に破棄される) 「Provisioned Concurrency」 メリット ・設定が簡単 ・コンテナ数をプロビジョニングできるため、大量のリクエストに対応できる デメリット ・Lambdaの実行とは別に料金がかかる ・コンテナを事前に立てておくだけの機能の為、DBのCnnectionが維持できない → DBのConnectionを維持する必要があるので、今回はAmazon EventBridgeでスケジュール実行させる方法を採用 ▼ 構築のPoint ・今回は複数のAPIを作成するため、一つずつEventBridgeの設定をしていくのは大変 → 全APIをたたくLambdaを新規作成し、そのLambdaのみスケジュール実行させる ・毎回ソース内の全ての処理が実行されると困る(毎回DBのデータが書き換えられたりする) → スケジュール実行のLambdaによって呼び出された場合は、通常実行時の処理を行う前にレスポンスを返すようにする 構成図は以下のようになる ▼ 実行時間を計測 「schedued-execution-lambda」をスケジュール実行させた状態で動作確認 実行時間 1回目 3625ミリ秒 2回目 473ミリ秒 3回目 633ミリ秒 4回目 376ミリ秒 5回目 574ミリ秒 3~5秒ほど短縮されていて、コールドスタートは回避できていそう それでもまだ目に見えて初回起動に時間がかかっているので、DB接続とクラスローディング対策を進めていく DBコネクション対策 スケジュール実行時にはDB処理を行っていない為、DBのConnectionが維持できていない 単純だが、スケジュール実行された場合の処理に、DB接続して閉じるだけの処理を追加する(現在はスケジュール実行によるHTTPリクエストの場合、通常の処理を行わずにすぐReturnさせている) ▼ 実行時間を計測 「schedued-execution-lambda」をスケジュール実行させた状態で動作確認 実行時間 1回目 1846ミリ秒 2回目 634ミリ秒 3回目 356ミリ秒 4回目 472ミリ秒 5回目 533ミリ秒 さらに2秒程度短縮されていることが確認できた ただ、これでもまだ実用できるほどの短縮にはなっていない為、クラスローディング対策も行う クラスローディング対策 ▼時間がかかっている処理を特定 ミリ秒単位で計測したいので、java.lang.SystemクラスのcurrentTimeMillis()メソッドを使用し、処理時間をログに出力させていく おそらく、ハンドラメソッドのあるクラス内で他のクラスを呼び出したりインスタンス化する処理に時間がかかっている ▼Staticイニシャライザを使用 Staticイニシャライザとは、 クラスのロード時に一度だけ実行されるstaticで宣言されたコードブロックのこと つまりここで一度読み込んでクラスをロード済みにしてしまえば、実行時のクラスローディングにかかる時間を短縮できる 初回起動で時間がかかっている処理をここにガシガシ書いていく ここにDB接続処理も書いておけば、「Provisioned Concurrency」も使えそう ▼ 実行時間を計測 「schedued-execution-lambda」をスケジュール実行させた状態で動作確認 実行時間 1回目 749ミリ秒 2回目 637ミリ秒 3回目 745ミリ秒 4回目 465ミリ秒 5回目 585ミリ秒 ついに1秒を切った、、、! まとめ JavaのLambdaの初回起動が遅い問題ですが、 ・コールドスタート対策 ・DBコネクションの維持 ・クラスローディング対策 を行うことで解消することができました 他にもできることがあれば教えていただきたいです。 こういったチューニングを行う際には裏側の理解が必要なので、歯ごたえがあって楽しいです!