2018年6月22日金曜日

AWS Lambda で環境変数を使用 暗号化と復号

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

最近、AWSをフル活用して社内システムを作ったので、そのノウハウのご紹介を行っています。

ただいま、Lambdaで関数作りを頑張っています。

環境変数を使用する

Lambda には環境変数をセットする項目があります。




環境変数を使用する用途としては、例えばソースにコミットするわけにはいかないパラメータの取り扱いですね。

WebAPIを使用するためのパスワードとかがそれに当たりますが、ソースや設定ファイルにパスワードを書いてコミットしておくとソースをチェックアウトする開発者全員にバレてしまいますから、環境変数にセットしておいておくことでソースには含めないわけです。

他には、私は「実行環境の場所」を判別するのにも便利です。

「ローカルで動作確認する時はこっち」「Lamda上でテストする時はこっち」「本番実行する時はこっち」と今、自分がどのモードで動いているのかを判別する材料として環境変数をセットしておくわけです。

デプロイ時にパラメータを切り替えると切り替え忘れたりしますが、環境変数にセットしておけばそんなことは心配無用ですからね。

その他、ログレベルを動的に変えるとか、使い方は色々。

サーバレスだからこそ、環境変数を便利に使うのがコツと言えると思います。


環境変数をセットして読み取り

では、実際に環境変数をセットしてみましょう。
セットは簡単。

キーと値をセットして終わり。



読み取る時は、その言語標準の方式で読み取ればOKです。
Pythonだとこうなります。

import os


def lambda_handler(event, context):
    param = os.getenv("test")

    # Tacy
    print(param)


簡単ですね。

暗号化

環境変数は暗号化することも出来ます。
暗号化したパラメータは後で復号することも可能です。

キーの作成と暗号化

まず、IAMのマネージメントコンソールから鍵を作成します。



そしてLambdaのコンソールから鍵をセットすると、何やら「暗号化」という項目が出てきましたね。



暗号化ボタンを押すと、もうどんな値が入っていたかは見えなくなります。



さて、後はこれをどうやって復号するかですが、実は「暗号」ボタンのすぐ右の「コード」というボタンを押すとすぐにサンプルソースが出てくるんですよ。

シークレットスニペットの復号

import boto3
import os

from base64 import b64decode

ENCRYPTED = os.environ['test']
# Decrypt code should run once and variables stored outside of the function
# handler so that these are decrypted once per container
DECRYPTED = boto3.client('kms').decrypt(CiphertextBlob=b64decode(ENCRYPTED))['Plaintext']

def lambda_handler(event, context):
  # TODO handle the event here

親切で助かりますね。

では、動作確認してみましょう。

動作確認ソース

import boto3
import os

from base64 import b64decode


def lambda_handler(event, context):
    ENCRYPTED = os.environ['test']

    # 390c9aa7-75f3-11e8-abe0-656e318945ae
    print(ENCRYPTED)

    DECRYPTED = boto3.client('kms').decrypt(CiphertextBlob=b64decode(ENCRYPTED))['Plaintext']

    # Tacy
    print(DECRYPTED.decode())

無事に出力されました。
特に問題は無さそうですね。

終わりに

案外簡単でした。
ただ、この環境変数って昔は無かったそうです。

2016年くらいにリリースされたみたいですね。

Lambdaはまだまだリアルタイムで進化形のサービスなのかもしれませんね。

2018年6月14日木曜日

【AWS Lambda】Lambda コスト節約論

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

最近、AWSをフル活用して社内システムを作ったので、そのノウハウのご紹介を行っています。

今回は気になるニュースを見たので雑談です。

ダイソーで予算超過危機が発生したらしい

ダイソーでLambdaを使ったら年間数千万円のコスト超過に陥るピンチになったらしいですね。


原因は Amazon DynamoDB だそうな。

Lambda と DynamoDB のコスト面での違い

記事を読むと、リスクの原因はLambdaとDynamoDBではコスト面の思想が違うことがキモであるようですね。

Lambdaは従量課金制

私がLambdaに着目する最大の理由ですが、Lambdaは使った分だけ支払う従量課金制です。

Lambdaではない通常のレンタルサーバの場合、サーバを丸ごと一台を借りて占有してしまうわけですから、使っていてもいなくても占有リソースは一定、従って料金は一定です。
つまり、夜中とか誰も使っていない時間帯でも金はそのまま取られているってことですよ。

想定される処理の最大負荷が8と仮定して、それに備えてサーバには10のリソースを割いているとします。
すると、サーバリソースは以下のように消費されます。

レンタルサーバの場合のリソース無駄使い
レンタルサーバの場合のリソース無駄使い

水色の部分が実際に必要なリソース。
グレーの部分はお金をドブに捨てている部分です。

負荷の最大/最小の差が大きいほど、このグレーゾーンは大きくなります。
「日中しか使わない社内システム」とか「人気ゲームの発売日直後だけ忙しくなる攻略Wiki」とか、かなり勿体ない使い方をしていると思います。

対して、Lambdaの場合はこんな感じ。

Lambdaの場合は無駄遣いが殆ど無い

グレーゾーンが殆どありません。

全く無いとは言いませんが、かなり細かい粒度で節約してくれるわけです。
素晴らしい。

DynamoDBは性能ベース

DynamoDBは「プロビジョニングベース」と言いまして、プロビジョニングとは何なのかはさておき、話の趣旨としては要するにこういうことです。

レンタルサーバの場合のリソース無駄使い
DynamoDBの場合のリソース無駄使い
DynamoDBは従量課金制ではない。

つまり、

  • APサーバであるLambdaは従量課金制かもしれないが、DBサーバであるDynamoDBは従量課金制ではない。
  • ダイソーのレジは「忙しい時間帯」と「暇な時間帯」があって、DynamoDBは暇な時間帯でも忙しい時間帯と同じ料金を取られる。
  • だからDynamoDBがコスト超過に陥る。

なんてこった。

どうすれば良いのか?

ダイソーの場合

クラウドの面白い所であるが欠点でもあるという所だと思いますが、クラウド環境ってこういう従来方式であれば考えなくて良い制約ってものがあるんですよ。

それを克服出来るかどうかがエンジニアの腕の見せ所。

記事を見ると、ダイソーの場合はLambdaを遅延させることでDynamoDBの最大負荷を下げて解決したようです。

リアルタイム性が必要無いのであれば、そのようなキュー方式を採用するのも一つのアイデアですね。

勉強になります。

S3を使ってはどうか?

ダイソーのキュー方式作戦は一つの正解だったと思いますが、要点はこういうことですよね。

  • 出来る限りDynamoDBの負荷を下げなければならない。

核心部分としては、DBサーバの負荷を下げる為のプログラムチューニングなわけですよ。

この記事を見た時は、私は直観で「DBを節約したいなら、ファイルでやればどうか?」と思いましたね。

昔、クラウドではないオンプレミス環境のシステムを作った頃の経験なんですけど、私は大量データ収集配布処理を作ったことがあるんですよ。
あの時は「DBで持つ情報」と「ファイルで持つ情報」を分類して管理していました。

  • データはDBではなくファイルで持つ。

この作戦です。

ファイルサーバに相当するAmazon S3は従量課金制だから、DynamoDBみたいボトルネックにはなりません。

ファイルで持つ情報

ファイルで情報を持つ大前提は「ファイルパスが一意キーである」ことです。

DBの用語で表現をするならば、主キー検索だけでしかアクセスしない情報はファイルで持てば良いのです。

DBで持つ情報

DBで持つ必要のある情報は、SQLですね。
「検索フォームから条件を入れて検索したい」とか「group by したい」みたいなSQLの機能があってこそ実現可能な要件のあるデータはDBで持つしかありません。

まあDynamoDBはNoSQLなのでちょっと違いますが、いずれにせよDynamoDBの中になければ使えない機能が必要なのであれば、DynamoDBに持つしかないです。

ダイソーはきっとこっちだったのでしょうね。

冗長に持つ

これは褒められた手段ではありませんが、状況によっては「殆ど主キー検索で使用するデータだけど、ちょっとだけgroup by したい時もある」みたいなケースもあります。

そういう時は、もう腹をくくって同じデータをファイルとDBの二重で持つのも一つの判断です。
データの不整合の余地を残すという弱点が生まれてしまいますが、チューニングには何かを犠牲にするという判断が必要になる時もあります。

ディスク使用量は問題ではない

私の経験則を一つ。
負荷という面において「ディスク使用量」というのは問題にはならんですよ。

あくまで一般論ですが、システムにおいて「ディスクスペース」ってのは安くて余裕があるものなのです。
だからディスクスペースを無駄遣いする代わりに別の部分を高速化するという手法は常套手段としてよく使います。

Amazonの場合もそうで、ファイルスペースであるS3に巨大データが居座っていることは問題にならんです。

  • 0.023USD/GB

1TB使って月23ドル
プロジェクト全体の予算から考えればゴミみたいなものでしょう?
低アクセス領域におけばもっと安い。

チューニングにおいては「どこがクリティカルなのか?」ということを分かっていなければなりません。

注意点ですが、ネットワーク転送量は別の話です。

大量データをS3に置いておくだけなら易いですが、それを無数のユーザにダウンロードさせるようなことをすると、ネットワーク料金がかさんで破産します。
だからダウンロード用データはAmazonではなく別の定額制の場所に置くとか、CDN(コンテンツデリバリネットワーク)を使うとかいった工夫が必要になります。

まあ、そこまで話が伸びるとキリが無いのでここで終わり。

まとめ

ここまで書いて思うこととしては、

  • クラウドはロジック効率がコストに跳ね返ってくる。

ということですね。

丸ごとドーンとサーバを貰っちゃってるオンプレミスとは条件が違いますから、処理効率を考案するアーキテクトの力量が非常に重要です。

ありとあらゆる創意工夫を総動員して総合的に効率的なシステムを構築しなければなりません。

となると、「実装が出来るだけ」みたいなドカタが背負えるようなものでは到底なくて、実装・DB・ネットワーク・AWS特性など色々な側面を平行して考慮出来るフルスタックエンジニアが求められてくるという……。

全く、IT業界は楽じゃないですね。

2018年6月1日金曜日

【AWS Lambda】関数作成4

株式会社ジェニシス 技術開発事業部の遠藤 太志郎(Tacy)です。

最近、AWSをフル活用して社内システムを作ったので、そのノウハウのご紹介を行っています。

現在はAWS Lambdaの使い方を紹介中です。

前回からまだまだ続いてLambda関数のコンソール画面を調査中です。

ネットワーク


ネットワークは、関数が置かれるネットワークの場所を指定する項目で、VPCを選択することが出来ます。


「VPCって何だ?」というところが問題ですね。


VPCは「Virtual Private Cloud」の略称です。プライベートクラウドです。

要するに、普通にAWSを使っている時、それはパブリッククラウドなのですよ。
インターネット上に存在しているAWSには世界中のどこからでも自由にアクセスして処理することが出来ます。

プライベートクラウドは、例えば「自社の中からしか接続できない」みたいに特定の場所からしかアクセスしか出来ないようにすることで、自分達専用のクラウド空間を実現するということです。

あくまでも仮想的にプライベート化するだけで、物理的には同じサーバに載っていますのでご注意を。

このVPCの設定は、どのネットワーク上に置くのか、ということを選択する項目です。
「非VPC」は普通のインターネットからアクセス可能という意味です。

デバッグとエラー処理


デバッグとエラー処理は、Lamdaがコケた時の通知です。
以下の二つを選択可能です。

  • SNS:Amazon Simple Notification Service
  • SQL:Amazon Simple Queue Service

SNSはFaceBookとかそういうのではないのでお間違え無く。

Lamdaはコケると再実行されるようですが、リトライが一定回数を超えた場合、上記のどちらかのサービスにメッセージを送ります。
これで保守担当に連絡が行って、障害を検知できるという機能ですね。

アクティブトレースとは、「AWS X-Ray」というサービスを活用してより詳細なログを追いかける機能の模様です。 

同時実行数


これは少し驚きでした。
AWS Lambdaは際限なくスケールアウトしていくものと思っていましたが、実際には同実行数1000という上限が設けられているそうです。

「予約されていないアカウントの同時実行の使用」と「同時実行の予約」という言葉がありますが、これはこういうことです。

まず、対象リージョンの対象アカウント毎に同時実行数は「1000」という閾値があり、Lambda関数を100コ作っても200コ作ってもこの同時実行数を消費して処理します。

何も設定しなければ1000ある椅子を早い者勝ちで取っていくわけですが、関数に依っては「大事だから確実に実行したい処理」とか「激増する可能性があるから限度を設けて締めておきたい」とかいう需要もあるかもしれません。

そのな時は、同時実行の値を100とか入れておきます。

すると、その処理の為に椅子が100コ確保されて、その処理はその100の中だけで行います。
他の処理は残り900を共有して行う。

こういう処理です。

よほどの大量アクセスが見込まれない限りはフリーで良いと思いますが、特別な事情がある時は使うことになりそうです。

監査とコンプライアンス


単なる注意書き。
Lambdaでは、監査やコンプライアンスの為に、その関数に対していつ誰が何をしたという証跡を「CloudTrail」という所に保存しているようです。

これにより「誰か知らんうちに何か変なことしやがった!!」って時に犯人を特定できるわけです。

終わり

これでザッと一通り目を通せました。

色々ありましたが、一つ一つはそんなに難しいわけでもなく、使いやすい良いサービスだと思います。

引き続き関数作りを進めていきます。