kasei_sanのブログ

かせいさんのIT系のおぼえがきです。胡乱の方はnoteとtwitterへ

lambdaプロキシ統合を使って、API Gatewayからlambdaへ各種パラメータを渡す方法

lambdaプロキシ統合って?

API Gatewayが受け取ったパラメータやリクエストヘッダなどの情報をlambdaのevent引数にわたすようにする方法

Lambda プロキシ統合では、クライアントが API リクエストを送信すると、API Gateway は、統合された Lambda 関数に raw リクエストをそのまま渡します。ただし、リクエストパラメータの順序は保持されません。このリクエストデータには、リクエストヘッダー、クエリ文字列パラメータ、URL パス変数、ペイロード、および API 設定データが含まれます。設定データには、現在のデプロイステージ名、ステージ変数、ユーザー ID、または承認コンテキスト (存在する場合) を含めることができます。

API Gateway の Lambda プロキシ統合をセットアップする - Amazon API Gateway

どうやって設定するの?

API Gateway作成時に「lambdaプロキシ統合」をonにする

f:id:kasei_san:20200214103917p:plain

lambdaプロキシ統合した時のevent引数の中身

API Gatewayで、 /create?branch_name=aaa&commit_hash=bbb というPATHを叩いた場合のevent引数の中身

{
  "resource": "/create",
  "path": "/create",
  "httpMethod": "GET",
  "headers": null,
  "multiValueHeaders": null,
  "queryStringParameters": {
    "branch_name": "aaa",
    "commit_hash": "bbb"
  },
  "multiValueQueryStringParameters": {
    "branch_name": [
      "aaa"
    ],
    "commit_hash": [
      "bbb"
    ]
  },
  "pathParameters": null,
  "stageVariables": null,
  "requestContext": {
    "resourceId": "*****",
    "resourcePath": "/create",
    "httpMethod": "GET",
    "extendedRequestId": "*****",
    "requestTime": "29/Jan/2020:08:28:51 +0000",
    "path": "/create",
    "accountId": "*****",
    "protocol": "HTTP/1.1",
    "stage": "test-invoke-stage",
    "domainPrefix": "testPrefix",
    "requestTimeEpoch": 1580286531393,
    "requestId": "*****",
    "identity": {
      "cognitoIdentityPoolId": null,
      "cognitoIdentityId": null,
      "apiKey": "test-invoke-api-key",
      "principalOrgId": null,
      "cognitoAuthenticationType": null,
      "userArn": "arn:aws:iam::*****:*****",
      "apiKeyId": "*****",
      "userAgent": "aws-internal/3 aws-sdk-java/1.11.690 Linux/4.9.184-0.1.ac.235.83.329.metal1.x86_64 OpenJDK_64-Bit_Server_VM/25.232-b09 java/1.8.0_232 vendor/Oracle_Corporation",
      "accountId": "*****",
      "caller": "*****",
      "sourceIp": "*****",
      "accessKey": "*****",
      "cognitoAuthenticationProvider": null,
      "user": "*****"
    },
    "domainName": "testPrefix.testDomainName",
    "apiId": "*****"
  },
  "body": null,
  "isBase64Encoded": false
}

クエリパラメータを取りたい場合

event['queryStringParameters']event['multiValueQueryStringParameters'] から取る

POSTされたデータを取りたい場合

event['body'] から取る。テキストデータで来るので、parseする必要があるので注意

AWS CodeBuild の buildspec.yml のコマンドで curl の完了前に処理が終了する件とその対策

buildspec.yml(一部)

post_buildcurl を実行後にその戻り値をチェックする command を実行する

実際のコードでは、API Gatewayを叩いていた

version: 0.2

phases:
  post_build:
    commands:
      - curl https://example.com
      - echo $?

実行結果

すると、 curl が完了する前に、次のコマンドが実行され、最終的に curl が完了する前に post_build が完了してしまう

[Container] 2020/02/04 01:51:29 Running command curl https://example.com

[Container] 2020/02/04 01:51:29 Running command echo $?
0

[Container] 2020/02/04 01:51:29 Phase complete: POST_BUILD State: SUCCEEDED
[Container] 2020/02/04 01:51:29 Phase context status code:  Message: 
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed

  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0curl: (6) Could not resolve host: example.com

原因

不明

対策

curlを使わないようにした

version: 0.2

phases:
  install:
    runtime-versions:
      ruby: 2.6

  post_build:
    commands:
      - ruby ./kick_api.rb
      - echo echo $?

kick_api.rb

require 'net/https'
require 'uri'

uri = URI.parse('https://example.com')
puts "Kick API: #{uri.to_s}"

res = Net::HTTP.get_response(uri)

puts "Responce code: #{res.code}"
puts "Responce body: #{res.body}"
res.value # 200以外なら例外を返す

node.jsのリリースサイクルについてメモ

まとめ

  • 6ヶ月に1度メジャーバージョンがリリースされる
  • 6ヶ月後に、奇数バージョンは放棄される
  • 偶数バージョンはLTS(Long Term Support)。通常、重大なバグが30ヶ月間は修正される  
  • 大企業や複雑なシステムはLTSを使うことを推奨
  • 最新機能を使いたい場合、最新版を使う

リリースサイクルのステータス

  • リリースサイクルのステータスは、CURRENT(最新)、ACTIVE(有効)、MAINTENANCE(保守) の3つ
  • CURRENT〜ACTIVEの間は更新され続け、MAINTENANCEの間は重大なバグは修正されつづける
  • リリース〜6ヶ月後: CURRENT
  • 6〜18ヶ月後: ACTIVE
  • 18〜30ヶ月後: MAINTENANCE

f:id:kasei_san:20200210101759p:plain
https://nodejs.org/ja/about/releases/

各バージョンのEOL

2020/02/10 現在

  • Node.js 10 〜 2021-04-30
  • Node.js 12 〜 2022-04-30
  • Node.js 13 〜 2020-06-01

参考

公式のリリースサイクルの説明

nodejs.org

curlは-fオプションをつけないとサーバエラーでも戻り値は0になる

サーバエラーが帰ってきても、curlの戻り値は0

$ curl -Is http://ozuma.sakura.ne.jp/httpstatus/500

HTTP/1.1 500 Internal Server Error
Server: nginx
Date: Tue, 04 Feb 2020 00:51:35 GMT
Content-Type: text/html; charset=utf-8
Connection: keep-alive
$ echo $?                                          
0

ozuma.sakura.ne.jp/httpstatus は任意のステータスコードを返してくれるサービス

ozuma.hatenablog.jp

ステータスコード200以外の時に、戻り値を0以外にしたい場合は、 -f オプションをつける

man curlより

-f, --fail
(HTTP) Fail silently (no output at all) on server errors. This is mostly done to better enable scripts etc to better deal with failed attempts. In normal cases when an HTTP server fails to  deliver  a document, it returns an HTML document stating so (which often also describes why and more). This flag will prevent curl from outputting that and return error 22.

This method is not fail-safe and there are occasions where non-successful response codes will slip through, especially when authentication is involved (response codes 401 and 407).
  • -f オプションをつけると、サーバエラーの場合戻り値は 22 にになり、標準出力になにも返さなくなる
  • ただし、 401や407のような認証系のエラーの場合、うまく動作しない場合がある とのこと

試してみる

$ curl -fs http://ozuma.sakura.ne.jp/httpstatus/500
$ echo $?                                          
22

そのとおりになった

dockerfileのARGの使い方おぼえがき

ARGとは

build実行時にオプション --build-arg として渡せる可変の値

使いみち

環境毎になにかを変える時に使用する

  • ビルド時に使用する環境変数
  • entrypoint.sh
  • COPY元

など

Dockerfileでの定義方法

ARG hoge="fuga"

解説

上記は、変数 hoge を時環境変数 HOGE に定義している

  • ARG 変数名 で変数を定義する。ここで定義しない変数は使用できない
  • ARG 変数名=デフォルト値 でデフォルト値も定義可能

変数展開方法

ENV HOGE=$hoge

$変数名 で変数展開される

build実行時に ARG に値を渡す方法

$ docker build . --build-arg hoge=fuga

docker-compose.yml に build-arg を定義する方法

buildargs に定義する

  app:
    build:
      args:
        hoge: fuga

そんなかんじ

Amazon Aurora serverless を知らなかった人が 2019/07 現在の Aurora serverless の最新状況を分かる範囲でまとめた

これの続編

blog.kasei-san.com

Amazon Aurora serverless って何?

インスタンスの管理が不要な Amazon Aurora

決して、serverless 専用の Aurora ではない

サポートしているエンジンは?

  • MySQL 5.6 互換の Amazon Aurora
  • PostgreSQL 10.7+ 互換の Amazon Aurora

Aurora と何が違うの?

  • シンプル
  • スケーラブル
  • 高コスト効率

シンプル

インスタンスの管理が不要なため、Auroraよりも更に運用コストが低下している

スケーラブル

  • 負荷に応じて、自動スケール & (設定によっては)自動停止する
  • Aurora Capacity Unit (ACU) という単位で課金される
    • 最低2、最大384
    • 0.1$/1ACU時間

高コスト効率

上記のスケーラブルのために、負荷が不安定だったり、決められた時間にしか使用しないサーバなどはAmazon Aurora serverlessでコストダウンできる

Amazon Aurora serverless が向いているサービス

  • 社内用のシステムなど、8-17以外の時間は停止しているサービス
  • バッチシステムのように、決められた時間以外は停止しているサービス
  • 開発/ステージング環境

Amazon Aurora serverless で注意すべきこと

  • 停止状態から再開するまでは1分程度掛かる
  • スケール時にはバッファプールがリセットされるため、再応答まで30秒程度掛かる
    • そのため、本番運用中にスケールするのはあまりよろしくない
  • Auroraの一部機能がサポートされていない
    • Amazon S3 バケットからのデータの読み込み
    • Aurora MySQL ネイティブ関数での AWS Lambda 関数の呼び出し
    • 高度な監査
    • Aurora レプリカ
    • バックトラック
    • データベースのクローン化
    • IAM データベース認証
    • クロスリージョンリードレプリカ
    • MySQL DB インスタンスからのスナップショットの復元
    • Amazon S3 からのバックアップファイルの移行
    • Amazon RDS パフォーマンスインサイト
  • リードレプリカが無いので、readだけやたら多いサービスの場合、むしろコスト効率が悪くなる?(要調査

参考リンク

dev.classmethod.jp

👆初回接続に22秒かかることを確認している

dev.classmethod.jp

👆ACU毎の最大コネクション数の調査

www.publickey1.jp

👆「スケールアップまたはスケールダウンは数秒で行われる一方、最初のインスタンスへの接続は25秒前後のレイテンシがあると説明されています」

qiita.com

👆一時停止→復帰、スケールが生じるとバッファプール(バッファキャッシュ)が初期化されるとのこと

感想

24/365で高負荷なサービスで運用するのには難しそう

ユースケースにあるとおり、低頻度利用環境向けのサービスと見るのが良さそう

AWS Systems Manager パラメータストアを使って、ECSのtaskで環境変数を安全に運用する方法

概要

DBのパスワードとかの機密情報をECSのtask実行時の環境変数に入れたい場合、AWS Systems Manager パラメータストアを使うとかんたん&安全

AWS Systems Manager パラメータストア is 何?

AWS Systems Manager パラメータストア は、設定データ管理と機密管理のための安全な階層型ストレージを提供します。パスワード、データベース文字列、ライセンスコードなどのデータをパラメータ値として保存することができます。値はプレーンテキストまたは暗号化されたデータとして保存できます。

ポイント

  • 値を暗号化して保管できる(暗号化はEKSで行われる)
  • APIを使って復号化した値を取得することができる

環境変数とかにパスワードとか入れたい時に便利!

AWS Secrets Manager シークレット というサービスもある

AWSで機密情報を扱いたい時にはどちらかを使えと公式ドキュメントにかかれている

機密データの指定 - Amazon ECS

Amazon ECS を使用すると、AWS Secrets Manager シークレットまたは AWS Systems Manager パラメータストアのパラメータに機密データを保存してコンテナの定義でそれを参照することによって、コンテナに機密データを挿入できます。

結局どちらが良いの?

こちらを参照しながら決めると良いかも

qiita.com

  • Secrets Managerの方が機能が多いけど有料(AWS Systems Managerも使い方によっては有料)
  • 昔はAWS Systems Manager パラメータストアは遅かったらしいが、現在は解決している様子

AWS Systems Manager のパラメータストアで、1 秒間に最大 1,000 件のリクエストがサポートされるようになりました。これにより、多数のパラメータに対してより高い同時アクセスが必要なアプリケーションを実行できるようになります

AWS Systems Manager がより高い API スループットでのパラメーターストアの使用のサポートを開始

ひとまずはAWS Systems Manager パラメータストアを使って、困ったらSecrets Managerに移行することにした

AWS Systems Manager パラメータストアのつかいかた

概要

  1. ロールの設定
  2. 機密情報の設定
  3. containerDefinitions の secrets にて呼び出す

1. ロールの設定

ECSを実行するロールに以下の権限を追加する

        "ssm:GetParameters",
        "kms:Decrypt"

自分の場合、今まで使用していたECS実行用のロールにインラインポリシーとしてアタッチした

(厳密にやるなら、アクセスできる機密情報の範囲をResourceで指定すること)

f:id:kasei_san:20190729093800p:plain

2. 機密情報の設定

AWS System Manager -> パラメータストア -> パラメータの作成 で設定できる

f:id:kasei_san:20190729094102p:plain

「安全な文字列」にしないと、暗号化されないので注意

f:id:kasei_san:20190729094324p:plain

よそのアカウントのKMSキーを使いたい場合は、「別のアカウント」にする

f:id:kasei_san:20190729094352p:plain

3. task Definition の containerDefinitions の secrets にて呼び出す

  • name に機密情報を格納する環境変数名を設定
  • valueFrom に AWS System Manager パラメータストアのパラメータのarnを入力する
    "containerDefinitions": [
        {
            "secrets": [
              {
                "name": "DATABASE_USERNAME",
                "valueFrom": "arn:aws:ssm:us-east-1:*********:parameter/DATABASE_USERNAME"
              },
              {
                "name": "DATABASE_PASSWORD",
                "valueFrom": "arn:aws:ssm:us-east-1:*********:parameter/DATABASE_PASSWORD"
              }
            ],

以上で、task実行時に環境変数に機密情報が格納されます!! 便利 & かんたん!!