DynamoDB + Lambda + SSM でテストサーバーをポコポコつくる仕組み

はじめまして。カヤック技術部の杉山です。 主にクライアントワークでサービスを開発しています。

今回は、クライアントワークで運用している、テストサイトの仕組みに関して書きます。

「テストサイト」の概要

クライアントワークでは、日々たくさんの案件を開発しています。 それぞれの案件では、多くの場合、Webサイトもしくは、WebAPIを公開するためのサーバーが必要になります。 実際の公開時には、案件ごとに専用のクラウドコンピューティングサービスを契約し、セットアップすることになりますが、 利用して良いサービスの確認が必要であったり、サービスの契約まで時間がかかったりするため、すぐには決まらない場合があります。そのため、開発時や検証時には、カヤック側でテストサイトを用意し、確認やプレビューを行っています。

さらに以下のような要望にも対応する必要があります。

  • 出来るだけ時間をかけず開発環境を用意したい
  • 案件ごとに、必要なミドルウェアが異なるため、出来るだけ汎用的なサーバーを用意する必要がある
  • WebSocketを利用する場合がある
  • Webサイトの表示にBASIC認証を設定する必要がある
  • 特定のユーザーのみがssh接続できるようにユーザー管理がしたい
  • git push 時に自動デプロイしたい
  • httpsで表示出来る必要がある
  • お金は節約したい

以上の条件から、サーバー構成の概要は以下のようにしました。

サーバー構成の概要図

この構成で、自動的に構築できる仕組みを作っています。

利用技術

  • Amazon DynamoDB
  • Amazon EC2 Simple Systems Manager (SSM)
  • Amazon CloudWatch
  • AWS Lambda
  • AWS Certificate Manager (ACM)

大まかな流れ

作成時

基本的な方針として、DynamoDBのトリガーを使うことで処理が行われるようにしています。

DynamoDBにセットアップ構成の書かれたレコードを追加すると、トリガーでLambda functionが呼び出されます。

レコードには以下のような情報を登録しています。

  • 公開されるドメイン
  • 登録日時
  • 削除日
  • 起動元となるAMI
  • ソースをCloneするリポジトリ・ブランチ
  • リポジトリ内で公開されるディレクトリ
  • BASIC認証のユーザー名・パスワード

まずAMIを元に、EC2インスタンスを起動させます。 EC2インスタンスが起動したイベントをトリガーに、さらに処理を続けます。

起動したEC2には、SSMエージェントがインストールしてあり、SSH接続することなく、 インスタンスIDの指定で、Lambda functionからコマンドを実行しセットアップを完了させています。

削除時

サイトが残り続けてしまわないように、CloudWatchによって、定期的にLambda functionを実行し、削除期限が切れているレコードを探し、削除します。 実際には、期限が切れそうになったら警告を送る、削除時にはAMIを作成、さらに一定期間で、AMIの削除ということも行っています。

細かい説明

SSM

実行先のEC2にSSMエージェントと、EC2のロールにAmazonEC2RoleforSSMポリシーを追加します。 実行元に、AmazonSSMFullAccessポリシーを追加すれば、任意のコマンドがInstanceIDの指定で実行できるようになります。

ユーザー管理

開発者がSSH接続できるようにユーザーを生成します。

Githubのリポジトリにアクセスできる、特定のTeamに所属するGithubユーザーを、Linuxユーザーとして作成します。 GithubのAPI経由で、User名・public keyを取得し、Linux Userとして登録しています。

自動デプロイ

Git Push 時に、自動でテストサイト内のプログラムを更新するため、 EC2内に、Git Pullを行うWebhook用のスクリプトを用意し、Supervisorで常時起動させています。

呼び出し側は、GithubのAPI経由で、そのアクセスURLを登録しています。

Git Pull 用の ssh key は、Lambda function上で生成し、Githubに登録、private key は EC2上に保存します。

https

証明書はACMでワイルドカード証明書を取得しています。 ACMが割り当てられるのは、CFかLBなので、ALBを置いて割り当てています。

ELBではなくALBを選択している理由は、WebSocketのサポートがあるためです。

どのテストサイトのドメインであっても、すべてALB経由でアクセスしたいので、 Route53で取得したドメインのサブドメインを、ワイルドカードの指定ですべてALBに割り当てています。

ALBにはホストベースのルーティング機能が無いので、ALBの後ろにEC2を置き、ルーティングを行っています。

basic認証

Basic認証の作成・更新は、 DynamoDBの更新のトリガーによって、 Lambda functionからSSMで.htpasswdファイルを書き換えています。

遅延実行

起動直後のEC2は、実際にはまだSSMコマンドが実行できず、少しの間待つ必要がありました。 遅延させてLambda functionを実行しています。

遅延実行には、SQSではなく、DynamoDBを使った遅延実行を実装しています。 SQSで遅延させることができる時間には制限があるためです。

DynamoDBに、実行するLambda function名、Payload、発火時間を設定し保存し、 CloudWatchによって、定期的にDynamoDBをチェックし、発火時間が来たときに、Lambda functionを呼び出しています。

DynamoDBへのレコード追加

最小限の工数で開発するため、初期開発ではコマンドラインツールを作成しました。 現在は構築した仕組みがうまく運用できているので、GUI版を開発し、テスト中です。

さいごに

以上、こんな仕組みになっていました。 実際作るよりも、移行までの計画や、どういう仕組みにするかを考える方が大変でした。

こんな仕事も面白そうだと思った人はこちらか ら! 杉山のブログを読んだと書いてもらえると、筆が進みます。

関連記事

techblog.kayac.com

techblog.kayac.com