AWSの日本サーバのIPアドレスのリストを得る

ツールのインストールなしで。 EC2サーバーなどのIPアドレスの範囲については、AWS公式がJSON形式で最新の情報を公開しています。 AWSのサーバ「からのアクセスを禁止したい」とか「からだけアクセスを許可したい」という時は、ここから対象となるサーバのリストを抽出することになります。 公式ドキュメントでは jq を使っ … 続きを読む

AWS CLIでVPC作成 | シンプライン株式会社

AWS CLIでVPC作成 | シンプライン株式会社. 1 users テクノロジー 記事元: www.simpline.co.jp …. AWS CLIでVPC作成 | シンプライン株式会社. 方針 jqは使用せず、AWS CLIで利用できるオプションをできる限り利用した。作成したものには全てNameタ… 続きを表示 方針 jqは使用せず、AWS CLIで利用できるオプションを … 続きを読む

Route53のヘルスチェック情報で月間合計ダウンタイムと稼働率を計算してみた

はじめに AWSチームのすずきです。 AWSが提供するDNSサービスのRoute53が備えるヘルスチェックを利用して、 Webサービスの月間の合計ダウンタイム時間を求め、 SLAなどの基準となる月間稼働率の計算を試みる機 […] 続きを読む

AWSの料金表を自動作成したい

AWS の料金一覧画面から Google スプレッドシートに値をコピペするのに疲れたので、なんとか EC2 の料金表を自動生成できないかと思いました。試行錯誤の結果、ようやくデータ構造までは把握できました。

AWS Price List Service API

AWS Price List Service API (AWS Price List Service)で AWS の料金データを取得できます。今回は取っ掛かりとして AWS CLI を使うので、Pricing サブコマンドでやることになります。

この API は、使えるエンドポイントが以下に限られます。

このため、.aws/config は以下のようにしています。

$ cat .aws/config
[default]
output = json
region = us-east-1

Pricing で使えるサブコマンドは、以下の3種類です。

サブコマンド名 機能
describe-services サービスとその属性名の一覧
get-attribute-values サービス毎の属性値の一覧
get-products 価格の一覧

describe-services

describe-services を何も指定せずに呼び出すと、サービスとその属性名の一覧がずらずらと表示されます。なお便宜上、(JSONではなく)テキスト形式で出力しています。

$ aws pricing describe-services --output=text | head -5
SERVICES        AWSBudgets
ATTRIBUTENAMES  productFamily
ATTRIBUTENAMES  servicecode
ATTRIBUTENAMES  groupDescription
ATTRIBUTENAMES  termType

いろんなサービスがありますね。。

$ aws pricing describe-services --output=text | grep ^SERVICES | wc -l
92
$ aws pricing describe-services --output=text | grep ^SERVICES | head -5
SERVICES        AWSBudgets
SERVICES        AWSCloudTrail
SERVICES        AWSCodeCommit
SERVICES        AWSCodeDeploy
SERVICES        AWSCodePipeline

今回目的とするサービス(EC2)の正式なサービス名を調べます。

$ aws pricing describe-services --output=text | grep -i ec2
SERVICES        AmazonEC2

これ以降は、コマンドを発行する際にサービスコードを明示することで、なるべくデータ量を減らすようにします。

AmazonEC2 サービスで使えそうな属性名の候補を調べます。

$ aws pricing describe-services --output=text --service-code AmazonEC2 | wc -l
62
$ aws pricing describe-services --output=text --service-code AmazonEC2 | 
  grep -Ei '(type|cpu|ecu|memory)'
ATTRIBUTENAMES  volumeType
ATTRIBUTENAMES  locationType
ATTRIBUTENAMES  ecu
ATTRIBUTENAMES  gpuMemory
ATTRIBUTENAMES  elasticGpuType
ATTRIBUTENAMES  memory
ATTRIBUTENAMES  vcpu
ATTRIBUTENAMES  termType
ATTRIBUTENAMES  instanceType
ATTRIBUTENAMES  usagetype

AmazonEC2 に限っても、ATTRIBUTENAME(属性名)だけで 62 個もある…。

get-attribute-values

次に “instanceType” という属性名に着目して、その属性値の候補を取得します。

$ aws pricing get-attribute-values --output=text --service-code AmazonEC2 
  --attribute-name instanceType | wc -l
122
$ aws pricing get-attribute-values --output=text --service-code AmazonEC2 
    --attribute-name instanceType | grep -E 't[12]'
ATTRIBUTEVALUES t1.micro
ATTRIBUTEVALUES t2.2xlarge
ATTRIBUTEVALUES t2.large
ATTRIBUTEVALUES t2.medium
ATTRIBUTEVALUES t2.micro
ATTRIBUTEVALUES t2.nano
ATTRIBUTEVALUES t2.small
ATTRIBUTEVALUES t2.xlarge

インスタンスタイプだけで 122 個…。この調子ですべての組み合わせを表示しようとすると、表のサイズが爆発するのは明白です。API サーバにも無意味に負荷をかけそうなので、最初はとりあえず t1.micro の Linux インスタンス(かつ東京リージョンのみ)に絞ってやってみています。

get-products

このサブコマンドで価格の値が取れるのですが、そのままでは使い勝手がよくありません。

$ aws pricing get-products --service-code AmazonEC2  
  --filters Type=TERM_MATCH,Field=instanceType,Value=t1.micro 
            Type=TERM_MATCH,Field=operatingSystem,Value=Linux 
            'Type=TERM_MATCH,Field=location,Value=Asia Pacific (Tokyo)' 
  > t1-micro-linux-tokyo.txt
$ cat t1-micro-linux-tokyo.txt
{
    "PriceList": [
        "{"product":{"productFamily":"Compute Instance","attributes":{"memory(以下、死ぬほど長い文字列)...

jq というコマンドを通すといい感じに整形してくれるらしいのですが、どうもうまくパースしてくれません。いろいろと試してみたところ、配列の中身全体が “” で囲まれているのが問題のようです。ということで、この引用符を外してやると、うまく見えるようになりました。ついでにバックスラッシュも外します。

$ cat t1-micro-linux-tokyo.txt | 
  sed -e 's/\//g' -e 's/"{/{/g' -e 's/}"/}/g' | 
  jq
{
  "PriceList": [
    {
      "product": {
        "productFamily": "Compute Instance",
        "attributes": {
          "memory": "0.613 GiB",
          "vcpu": "1",
          "instanceType": "t1.micro",
          "tenancy": "Shared",
          "usagetype": "APN1-BoxUsage:t1.micro",
          "locationType": "AWS Region",
          "storage": "EBS only",
          "normalizationSizeFactor": "0.5",
          "instanceFamily": "Micro instances",
          "operatingSystem": "Linux",
          "servicecode": "AmazonEC2",
          "physicalProcessor": "Variable",
          "licenseModel": "No License required",
          "ecu": "Variable",
          "currentGeneration": "No",
          "preInstalledSw": "NA",
          "networkPerformance": "Very Low",
          "location": "Asia Pacific (Tokyo)",
          "servicename": "Amazon Elastic Compute Cloud",
          "processorArchitecture": "32-bit or 64-bit",
          "operation": "RunInstances"
        },
        "sku": "ERVWZ4V3UBYH4NQH"
      },
      "serviceCode": "AmazonEC2",
      "terms": {
        "OnDemand": {
          "ERVWZ4V3UBYH4NQH.JRTCKXETXF": {
            "priceDimensions": {
              "ERVWZ4V3UBYH4NQH.JRTCKXETXF.6YS6EN2CT7": {
                "unit": "Hrs",
                "endRange": "Inf",
                "description": "$0.026 per On Demand Linux t1.micro Instance Hour",
                "appliesTo": [],
                "rateCode": "ERVWZ4V3UBYH4NQH.JRTCKXETXF.6YS6EN2CT7",
                "beginRange": "0",
                "pricePerUnit": {
                  "USD": "0.0260000000"
                }
              }
            },
            "sku": "ERVWZ4V3UBYH4NQH",
            "effectiveDate": "2017-12-01T00:00:00Z",
            "offerTermCode": "JRTCKXETXF",
            "termAttributes": {}
          }
        },
        "Reserved": {
          "ERVWZ4V3UBYH4NQH.NQ3QZPMQV9": {
            "priceDimensions": {
              "ERVWZ4V3UBYH4NQH.NQ3QZPMQV9.2TG2D8R56U": {
                "unit": "Quantity",
                "description": "Upfront Fee",
                "appliesTo": [],
                "rateCode": "ERVWZ4V3UBYH4NQH.NQ3QZPMQV9.2TG2D8R56U",
                "pricePerUnit": {
                  "USD": "316"
                }
              },
              "ERVWZ4V3UBYH4NQH.NQ3QZPMQV9.6YS6EN2CT7": {
                "unit": "Hrs",
                "endRange": "Inf",
                "description": "USD 0.0 per Linux/UNIX (Amazon VPC), t1.micro reserved instance applied",
                "appliesTo": [],
                "rateCode": "ERVWZ4V3UBYH4NQH.NQ3QZPMQV9.6YS6EN2CT7",
                "beginRange": "0",
                "pricePerUnit": {
                  "USD": "0.0000000000"
                }
              }
            },
            "sku": "ERVWZ4V3UBYH4NQH",
            "effectiveDate": "2015-04-30T23:59:59Z",
            "offerTermCode": "NQ3QZPMQV9",
            "termAttributes": {
              "LeaseContractLength": "3yr",
              "OfferingClass": "standard",
              "PurchaseOption": "All Upfront"
            }
          },
          "ERVWZ4V3UBYH4NQH.6QCMYABX3D": {
            "priceDimensions": {
              "ERVWZ4V3UBYH4NQH.6QCMYABX3D.2TG2D8R56U": {
                "unit": "Quantity",
                "description": "Upfront Fee",
                "appliesTo": [],
                "rateCode": "ERVWZ4V3UBYH4NQH.6QCMYABX3D.2TG2D8R56U",
                "pricePerUnit": {
                  "USD": "138"
                }
              },
              "ERVWZ4V3UBYH4NQH.6QCMYABX3D.6YS6EN2CT7": {
                "unit": "Hrs",
                "endRange": "Inf",
                "description": "USD 0.0 per Linux/UNIX (Amazon VPC), t1.micro reserved instance applied",
                "appliesTo": [],
                "rateCode": "ERVWZ4V3UBYH4NQH.6QCMYABX3D.6YS6EN2CT7",
                "beginRange": "0",
                "pricePerUnit": {
                  "USD": "0.0000000000"
                }
              }
            },
            "sku": "ERVWZ4V3UBYH4NQH",
            "effectiveDate": "2015-04-30T23:59:59Z",
            "offerTermCode": "6QCMYABX3D",
            "termAttributes": {
              "LeaseContractLength": "1yr",
              "OfferingClass": "standard",
              "PurchaseOption": "All Upfront"
            }
          },
          "ERVWZ4V3UBYH4NQH.38NPMPTW36": {
            "priceDimensions": {
              "ERVWZ4V3UBYH4NQH.38NPMPTW36.2TG2D8R56U": {
                "unit": "Quantity",
                "description": "Upfront Fee",
                "appliesTo": [],
                "rateCode": "ERVWZ4V3UBYH4NQH.38NPMPTW36.2TG2D8R56U",
                "pricePerUnit": {
                  "USD": "100"
                }
              },
              "ERVWZ4V3UBYH4NQH.38NPMPTW36.6YS6EN2CT7": {
                "unit": "Hrs",
                "endRange": "Inf",
                "description": "Linux/UNIX (Amazon VPC), t1.micro reserved instance applied",
                "appliesTo": [],
                "rateCode": "ERVWZ4V3UBYH4NQH.38NPMPTW36.6YS6EN2CT7",
                "beginRange": "0",
                "pricePerUnit": {
                  "USD": "0.0090000000"
                }
              }
            },
            "sku": "ERVWZ4V3UBYH4NQH",
            "effectiveDate": "2016-10-31T23:59:59Z",
            "offerTermCode": "38NPMPTW36",
            "termAttributes": {
              "LeaseContractLength": "3yr",
              "OfferingClass": "standard",
              "PurchaseOption": "Partial Upfront"
            }
          },
          "ERVWZ4V3UBYH4NQH.HU7G6KETJZ": {
            "priceDimensions": {
              "ERVWZ4V3UBYH4NQH.HU7G6KETJZ.2TG2D8R56U": {
                "unit": "Quantity",
                "description": "Upfront Fee",
                "appliesTo": [],
                "rateCode": "ERVWZ4V3UBYH4NQH.HU7G6KETJZ.2TG2D8R56U",
                "pricePerUnit": {
                  "USD": "62"
                }
              },
              "ERVWZ4V3UBYH4NQH.HU7G6KETJZ.6YS6EN2CT7": {
                "unit": "Hrs",
                "endRange": "Inf",
                "description": "Linux/UNIX (Amazon VPC), t1.micro reserved instance applied",
                "appliesTo": [],
                "rateCode": "ERVWZ4V3UBYH4NQH.HU7G6KETJZ.6YS6EN2CT7",
                "beginRange": "0",
                "pricePerUnit": {
                  "USD": "0.0090000000"
                }
              }
            },
            "sku": "ERVWZ4V3UBYH4NQH",
            "effectiveDate": "2015-04-30T23:59:59Z",
            "offerTermCode": "HU7G6KETJZ",
            "termAttributes": {
              "LeaseContractLength": "1yr",
              "OfferingClass": "standard",
              "PurchaseOption": "Partial Upfront"
            }
          },
          "ERVWZ4V3UBYH4NQH.4NA7Y494T4": {
            "priceDimensions": {
              "ERVWZ4V3UBYH4NQH.4NA7Y494T4.6YS6EN2CT7": {
                "unit": "Hrs",
                "endRange": "Inf",
                "description": "Linux/UNIX (Amazon VPC), t1.micro reserved instance applied",
                "appliesTo": [],
                "rateCode": "ERVWZ4V3UBYH4NQH.4NA7Y494T4.6YS6EN2CT7",
                "beginRange": "0",
                "pricePerUnit": {
                  "USD": "0.0180000000"
                }
              }
            },
            "sku": "ERVWZ4V3UBYH4NQH",
            "effectiveDate": "2016-08-31T23:59:59Z",
            "offerTermCode": "4NA7Y494T4",
            "termAttributes": {
              "LeaseContractLength": "1yr",
              "OfferingClass": "standard",
              "PurchaseOption": "No Upfront"
            }
          }
        }
      },
      "version": "20180131042456",
      "publicationDate": "2018-01-31T04:24:56Z"
    }
  ],
  "FormatVersion": "aws_v1"
}

返されるデータの構造がわかったので、後は必要な項目だけを抜き出して CSV で出力してやれば、Google スプレッドシートにインポートで取り込めそうです。ということで、今日はここまでです。


っと、ここまで書いてから投稿しようとしたら、AWS Price List API の使用 とかいうよさげなページがあるのに気づいたのでこれから読みます。。。

(参照)

続きを読む

より美しくWP Offload S3 Liteに既存のメディアを登録する方法

解決したい課題

すでに運用中のwordpressサイトがあります。コンテンツが増加し動画などのメディアファイルが多くなってきて、apacheで配信しているとサイトがどんどん重くなってしまいます。

WP Offload S3 Liteプラグインを導入して新しいメディアファイルはS3から配信されるようになりましたが、既存の大量のメディアファイルをS3から配信するにはどうすればいいのか?

という問題に遭遇したので対応方法を残しておきます。

方法2:SQLでなんとかする方法(NG)

同じようなことでお困りの方が結構いらっしゃるのでググると対応方法が出てきます。その多くはSQLでpost, post_metaを直接書き換える方法がほとんどです。
ですが、レコード内の設定内容はPHPでシリアライズされており、文字数などの記録されています。
正しく書き込むには新しい内容を正しくシリアライズしなくてはいけません。
そのためにプログラムを書かなければいけないのがデメリットです。

方法2: wp_cliでなんとかする。(better)

wb_cliはwordpressの為のコマンドラインインターフェースです。オプション豊富で様々な操作が可能です。これを使ってやってみました。

wp_contents/uploadsの内容ををAWSに転送

aws cliで一発です。

aws s3 sync wp-content/uploads/ s3://awesome-site.hoge.com/wp-content/uploads/

お決まりですが、S3バケットを作成してIAMを作成して、必要な権限だけ与えてください。
{{ bucket_name }}の部分を実際のバケット名に置き換えてください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:CreateBucket",
                "s3:DeleteObject",
                "s3:Put*",
                "s3:Get*",
                "s3:List*"
            ],
            "Resource": [
                "arn:aws:s3:::{{ bucket_name }}",
                "arn:aws:s3:::{{ bucket_name }}/*"
            ]
        }
    ]
}

もう少し権限絞りたい気もしますが、Get/PutのみだとPluginから権限がないと怒られます。

post_metaにS3のパスを正しく記録する

プラグインを入れてからメディアファイルをアップロードすると
post_metaにS3のパスが記録されます。

そこで正しいpost_metaを書き込んであげることで、プラグインに正しくファイルの位置を教えることができます。

メディアファイルのIDを取得する

ここで処理したいのはすべてのmediaファイルです。
メディアファイルのPOST_IDをすべて取得するには、以下のコマンドを使えばいいみたいです。

メディアファイルはpost_typeがattachmentです。

./bin/wp-cli.phar post list --post_type=attachment --format=ids

これを配列にいれてLOOPで処理すれば良さそうです。

メディアファイルのパスを取得する。

postテーブルのレコードのなかでguidというフィールドにhttp://から始まるURIが書かれています。

このような形式で記録されています。

./bin/wp-cli.phar post get 6802
+-----------------------+-----------------------------------------------------------------------------+
| Field                 | Value                                                                       |
+-----------------------+-----------------------------------------------------------------------------+
| ID                    | 6802                                                                        |
| post_author           | 1                                                                           |
| post_date             | 2018-01-30 18:20:09                                                         |
| post_date_gmt         | 2018-01-30 09:20:09                                                         |
| post_content          |                                                                             |
| post_title            | 20130705170431                                                              |
| post_excerpt          |                                                                             |
| post_status           | inherit                                                                     |
| comment_status        | open                                                                        |
| ping_status           | open                                                                        |
| post_password         |                                                                             |
| post_name             | 20130705170431                                                              |
| to_ping               |                                                                             |
| pinged                |                                                                             |
| post_modified         | 2018-01-30 18:20:09                                                         |
| post_modified_gmt     | 2018-01-30 09:20:09                                                         |
| post_content_filtered |                                                                             |
| post_parent           | 0                                                                           |
| guid                  | http://awsome-site.hoge.com/wp-content/uploads/2018/01/20130705170431.png |
| menu_order            | 0                                                                           |
| post_type             | attachment                                                                  |
| post_mime_type        | image/png                                                                   |
| comment_count         | 0                                                                           |
+-----------------------+-----------------------------------------------------------------------------+

必要なのはguidの中にあるcontent/uploads/内のパスですので、正規表現を使って
http://xxx.hoge.com/ みたいなプロトコル・ドメイン名を外します。

./bin/wp-cli.phar post get $ID --field=guid | sed -e 's/(http:.*)/(wp-content.*)/2/'

jqを使ってpost_metaを生成する

プラグインを入れた後にメディアファイルを追加すると以下のようなレコードがpost_metaに生成されます。KEYはamazonS3_infoです。

./bin/wp-cli.phar post meta get 6802 amazonS3_info

3つの情報が記録されています。これを新たに生成してあげればよいわけです。

array (
  'bucket' => 'site.hoge.com',
  'key' => 'wp-content/uploads/2018/01/30182009/20130705170431.png',
  'region' => 'ap-northeast-1',
)

正しいJSONを生成したいので、みんなが大好きなjqを使ってゼロからJSONを構築します。
jqはAWS CLIの結果をJSONでもらって、いろんなフィルタしたりするのに使うことが多いですが、シェルスクリプトからJSONを生成するにも便利です。

実際に実行すると、このような結果が得られます。

jq -Mncr ".bucket = "bucket-name" | .key = "GUID" | .region = "ap-northeast-1""
{"bucket":"bucket-name","key":"GUID","region":"ap-northeast-1"}

こうして生成したJSONを変数にいれて、wp-cliを使ってpost_metaを追加します。

JSON=`jq -Mncr ".bucket = "$BUCKET" | .key = "$GUID" | .region = "ap-northeast-1""`
echo $JSON | ./bin/wp-cli.phar post meta add $ID amazonS3_info --format=json

ちなみにpost_metaを削除することも可能です。

./bin/wp-cli.phar post meta delete $ID amazonS3_info

出来上がり

でき当たったシェルスクリプトがこれです。
すべてのメディアファイルをWP Offload S3 LiteをつかってS3で配信することができるようになりました。

#!/bin/bash

ARRAY=(`./bin/wp-cli.phar post list --post_type=attachment --format=ids`)
for ID in "${ARRAY[@]}"; do
    GUID=`./bin/wp-cli.phar post get $ID --field=guid | sed -e 's/(http:.*)/(wp-content.*)/2/'`
    BUCKET='bucket-name.hoge.com'
    JSON=`jq -Mncr ".bucket = "$BUCKET" | .key = "$GUID" | .region = "ap-northeast-1""`
    echo $JSON | ./bin/wp-cli.phar post meta add $ID amazonS3_info --format=json
done

続きを読む

オートヒーリングでゆるーくEIPもヒーリングしてみた

region=$(curl -s http: //169 .254.169.254 /latest/meta-data/placement/availability-zone | sed -e ‘s/.$//’ ). export AWS_DEFAULT_REGION=${region}. allocation_id=$(aws ec2 describe-instances –instance- id ${instance_id} | jq -r ‘.Reservations[].Instances[].Tags[] | select(.Key == “allocation-id”).Value’ ). 続きを読む

LocalStack導入から実行まで

はじめに

最近、AWS API GateWay + Lambdaを使用して、サーバレスでWeb APIを作成する機会がありました。
AWS コンソールから関数の作成、コードの編集を行う、といった体制で進めていましたが、一つの問題が出ました。

それが「コード書き換えてしまう問題」です

具体的に説明しますと、作業者AがとあるLambda関数を編集中に、作業者Bが同じLambda関数を更新しました。
その後、作業者Aが編集内容を更新すると、作業者Bの編集した内容が消えてしまうという問題です。
当時はバージョンの発行を行なっておらず、消えてしまったコードを遡ることができませんでした(このことを機にバージョン発行を覚えました)

元々、Lambdaで作成したソースコードをGitで管理したい、ローカル環境でテストしてから反映したい、等の意見を頂いていたので、ローカルによるLambda関数の実行、バージョンの管理をテーマに調べました、

そこで出会ったのがLocalStackでした。

LocalStackとは

LocalStackは、ローカルにAWSのモック/テスト環境を作ってくれてるツールです。

イメージとしては、ローカルに擬似的なAWS環境を作ってくれて、料金など気にせずにテストや
動作確認を可能にしてくれます。
他にもツールはありましたが、LocalStackの導入が比較的簡単そうであったため、今回はこれを使用します。

要件

  • ローカルにてLambda関数の実行
  • ソースコードをGitにて管理
  • AWS Lambda反映時に自動でバージョンを作成

環境

  • OS: macOS High Sierra(10.13.2)
  • Lambda ランタイム: Python3.6

事前準備

docker, docker-composeのインストール

公式サイトはコチラ

aws-cliのインストール

$ brew install awscli

aws アクセスキーの発行

公式サイトにて方法が記載されているので、各自発行してください。

aws プロファイルの設定

$ aws configure --profile localstack

AWS Access Key ID [None]: アクセスキー
AWS Secret Access Key [None]: シークレットキー
Default region name [None]: ap-northeast-1
Default output format [None]: text

jqコマンドのインストール

$ brew install jq

LocalStack導入手順

LocalStackインストール&起動

$ git clone https://github.com/localstack/localstack
$ cd localstack
$ TMPDIR=/private$TMPDIR docker-compose up -d

上記実行後、http://localhost:8080にてlocalstackのダッシュボート表示

スクリーンショット 2018-01-23 17.35.16.png

Lambda関数作成

$ mkdir 任意の作業ディレクトリ名
$ cd 任意の作業ディレクトリ名
$ vi lambda.py
lambda.py
# サンプルコードです
def lambda_handler(event, context):
    return 'Hello from Lambda'

localstack上にLambda関数を作成

  1. zipで固める
$ zip lambda.zip lambda.py
  1. localstack上に作成
$ aws --endpoint-url=http://localhost:4574 --region ap-northeast-1 --profile localstack lambda create-function --function-name="作成する関数名" --runtime=python3.6 --role="実行ロール名" --handler=lambda.lambda_handler --zip-file fileb://lambda.zip

スクリーンショット 2018-01-24 11.01.33.png

lambda関数実行

$ aws lambda --endpoint-url=http://localhost:4574 invoke --function-name "実行する関数名" --payload '{"key1":"value1", "key2":"value2", "key3":"value3"}' result.log
200

200が返って来たら成功

レスポンスの確認

$ cat result.log | jq

result.logをjqコマンドでJSON形式に変換して出力することで確認できます。


localstack上のlambda関数の一覧取得

$ aws --endpoint-url=http://localhost:4574 --region ap-northeast-1 --profile localstack lambda list-functions

localstack上のlambda関数の削除

$ aws --endpoint-url=http://localhost:4574 --region ap-northeast-1 --profile localstack lambda delete-function --function-name "削除する関数名"

localstack上のlambda関数の更新

$ aws --endpoint-url=http://localhost:4574 --region ap-northeast-1 --profile localstack lambda update-function-code --profile localstack --function-name "更新する関数名" --zip-file fileb://lambda.zip --publish

感想

dockerでローカルにawsテスト用のエンドポイントを作成し、awscliでlambda関数をLocalStackにあげて実行するような形です。
コマンドが少し長くて大変ですが、そこはエイリアスを設定したりでカバーできたらと思っています。
lambda関数の実行/作成/削除/更新のコマンドオプションに--endpoint-url=http://localhost:4574という指定があります。
これがLocalStackでの実行を指定しており、このオプションをつけないことによって、運用しているAWSに対して直接lambda関数の作成や更新など行うことができるため、localでテストしてすぐ本番に反映できるような感じです。
lambda関数更新時は、Lambda側が勝手にバージョンを作成してくれるため、Lambda側のバージョン管理も簡単にできるように感じました。

落とし穴

Lambdaにて関数を作成した場合、ファイル名はlambda_function.拡張子で固定されています。
ローカルでファイル名をhogehoge.pyのように適当につけて、既存lambda関数に対して更新をかけると、ファイルがないと怒られて動かなくなるため、注意が必要です。(テスト環境が一時停止して結構焦りました。)


参考サイト

続きを読む

[AWS] ELBとEC2の tag:Name の仕様の違いについて

細かい点ですが、EC2とELBの所謂「Nameタグ」の仕様に違いがあったのでまとめておきます。

EC2の場合

コンソールでEC2を確認すると、一覧と「タグ」タブ内に2つ”Name”が確認できます。EC2では、この2つは同じものです。

image.png

これは実体としてはタグで、describe-instancesコマンドで確認できます。

$ aws ec2 describe-instances --region eu-west-3 | jq -r '.Reservations[] .Instances[] .Tags[]'
{
  "Value": "bastion-ec2",
  "Key": "Name"
}

更新したい場合は、create-tagsコマンドで(少々違和感がありますが)上書きできます。

$ aws ec2 create-tags --region eu-west-3 --resources i-02axxxxxxxxxxxxx --tags Key=Name,Value=name-update-test

コンソールでは両方更新されることが確認できます。

image.png

ELBの場合

コンソールでELBを確認すると、一覧の方に”名前”が、「タグ」タブの方に”Name”が表示されています。EC2と似た表示ですが、ELBではこれらは別物です。

image.png

“名前”の方はロードバランサ名(LoadBalancerName)でdescribe-load-balancersコマンドで確認できます。”Name”の方がタグで、describe-tagsコマンドで確認できます。

$ aws elb describe-load-balancers --region eu-west-3 | jq -r '.LoadBalancerDescriptions[] .LoadBalancerName'
internal-elb
$ aws elb describe-tags --region eu-west-3 --load-balancer-names internal-elb
{
    "TagDescriptions": [
        {
            "Tags": [
                {
                    "Value": "this-is-name-tag",
                    "Key": "Name"
                }
            ],
            "LoadBalancerName": "internal-elb"
        }
    ]
}

ロードバランサ名(LoadBalancerName)の方は、作成後には更新できません。タグの方はEC2と同様にadd-tagsコマンドで上書きできます。

$ aws elb add-tags --region eu-west-3 --load-balancer-names internal-elb --tags Key=Name,Value=tag-update-test
$ aws elb describe-tags --region eu-west-3 --load-balancer-names internal-elb
{
    "TagDescriptions": [
        {
            "Tags": [
                {
                    "Value": "tag-update-test",
                    "Key": "Name"
                }
            ],
            "LoadBalancerName": "internal-elb"
        }
    ]
}

コンソールでもタグの方だけ更新されたことが確認できます。

image.png

ALBまたはNLBの場合

ALB(Application Load Balancer)またはNLB(Network Load Balancer)の場合も同様の動作となります。awscliはelbv2コマンドで確認できます。

名前とタグの確認:

$ aws elbv2 describe-load-balancers --region ap-northeast-1 | jq -r '.LoadBalancers[] .LoadBalancerName'
internal-elb
$ aws elbv2 describe-tags --region ap-northeast-1 --resource-arns arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxx:loadbalancer/net/internal-elb/xxxxxxxxxx
{
    "TagDescriptions": [
        {
            "ResourceArn": "arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxx:loadbalancer/net/internal-elb/xxxxxxxxxx",
            "Tags": [
                {
                    "Value": "this-is-name-tag",
                    "Key": "Name"
                }
            ]
        }
    ]
}

タグの変更:

$ aws elbv2 add-tags --region ap-northeast-1 --tags Key=Name,Value=tag-update-test --resource-arns arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxx:loadbalancer/net/internal-elb/xxxxxxxxxx
$ aws elbv2 describe-tags --region ap-northeast-1 --resource-arns arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxx:loadbalancer/net/internal-elb/xxxxxxxxxx
{
    "TagDescriptions": [
        {
            "ResourceArn": "arn:aws:elasticloadbalancing:ap-northeast-1:xxxxxxxxxx:loadbalancer/net/internal-elb/xxxxxxxxxx",
            "Tags": [
                {
                    "Value": "tag-update-test",
                    "Key": "Name"
                }
            ]
        }
    ]
}

まとめ

EC2の場合は特に意識せず「Nameタグ」を使っていましたが、ELBの場合は名前(LoadBalancerName)とタグ(tag:Name)が別々に設定できるので混同しないよう注意が必要です。違う値を設定した場合はどちらを意図しているのかきちんと確認するようにしましょう。

続きを読む