この記事はClojure Advent Calendar 2015の21日目の記事です。
ClojureとAWS Lambdaを使って何かできないかを考えるのがマイブームなのですが、amazonicaを使うとAWSのリソースに簡単にアクセスできるのが分かったので、amazonicaを使って定期的にEBSスナップショットを作成するLambda Functionを作ってみます。
EBSスナップショット関連のamazonicaの関数
amazonicaのgithubには代表的な関数の呼び出し方の例は記載されていますが、包括的なリファレンスがどこにあるのか分からない!ということで、Lambda Functionを作る前に、replであたりをつけます。
EBSスナップショットを作成。
(def cred {:access-key "YOUR_ACCESS_KEY"
:secret-key "YOUR_SECRET_KEY"
:endpoint "ap-northeast-1"})
(amazonica.aws.ec2/create-snapshot cred :volume-id "vol-a1b2c3d4"
:description "vol-a1b2c3d4-snapshot-2015-12-21-16-50")
スナップショットにタグをつける。
(amazonica.aws.ec2/create-tags cred :resources ["snap-a1b2c3d4"]
:tags [{:key "Name"
:value "vol-a1b2c3d4-snapshot-2015-12-21-16-50"}])
スナップショットを削除。
(amazonica.aws.ec2/delete-snapshot cred :snapshot-id "snap-a1b2c3d4")
Lambda Functionを登録してみる。
とりあえず意図したとおりにLambda Functionの定期実行でスナップショットをとれるかどうかを確認するため、AWSのアクセスキーや対象のVolume IDはハードコードしてしまってLambda Functionを登録してみます。
; src/lambdabackup/ec2.clj
(ns lambdabackup.ec2
(:gen-class
:implements [com.amazonaws.services.lambda.runtime.RequestStreamHandler])
(:require [clojure.java.io :as io]
[amazonica.aws.ec2 :as ec2]))
(def cred {:access-key "YOUR_ACCESS_KEY"
:secret-key "YOUR_SECRET_KEY"
:endpoint "ap-northeast-1"})
(def volume-id "vol-a1b2c3d4")
(defn -handleRequest [this is os context]
(let [name "test-backup"
snapshot (ec2/create-snapshot cred
:volume-id volume-id
:description name)
snapshot-id (get-in snapshot [:snapshot :snapshot-id])]
(ec2/create-tags cred
:resources [snapshot-id]
:tags [{:key "Name" :value name}])
(let [w (io/writer os)]
(.write w snapshot-id)
(.flush w))))
project.clj
はこんな感じ。
(defproject lambdabackup "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.7.0"]
[com.amazonaws/aws-lambda-java-core "1.0.0"]
[amazonica "0.3.41"]]
:aot :all)
standaloneなjarを作成。
$ lein ubarjar
jarをアップロードし、Lambda Functionを新規作成。--role
はこの記事を書いたときに作ったRoleを再利用しました。
$ aws lambda create-function --function-name ebs-create-snapshot --handler lambdabackup.ec2::handleRequest --runtime java8 --memory 512 --timeout 60 --role arn:aws:iam::AWS_ACCOUNT_ID:sandbox-lambda-exec-role --zip-file fileb://./target/lambdabackup-0.1.0-SNAPSHOT-standalone.jar
jarを更新する場合には、
$ lein ubarjar
$ aws lambda update-function-code --function-name ebs-create-snapshot --zip-file fileb://./target/lambdabackup-0.1.0-SNAPSHOT-standalone.jar
AWS LambdaのWebコンソールでテストを実行したところ、スナップショットを作成することはできているようなので、同じくWebコンソールのLambda > Functions > FUNCTION_NAME > Scheduled Eventを登録しました。(本当はCLIでやりたかったが方法がぱっと分からず。)
TODO
Clojure力とAWS Lambda力が低すぎて、アドベントカレンダーの期日までには解決できなかったことがたくさん残っています。
- AWSのアクセストークンをハードコードしているのは何とかならないか?
- Lambdaを実行しているRoleに権限を付与すれば消せるだろうか?
- Volume IDをハードコードしているのは何とかならないか?
- LambdaのScheduled Eventに任意の引数を含められれば消せそうだが、そういう機能はなさそう。
- 毎回
com.amazonaws.services.lambda.runtime.RequestStreamHandler
を実装するは無駄なので、もう少し省エネでハンドラーを書きたい。 - スナップショット作成に失敗した場合の処理をなんとかしたい。
- 保持するスナップショット数を一定の世代数に制限して、不要になったスナップショットを削除するLambda Functionもamazonicaで実装したい。
参考URL
- https://github.com/mcohen01/amazonica
- ClojureとAWS LambdaでHello World
- [AWS LambdaからPythonでEC2のインスタンスを起動するスケジュールを設定してみた #reinvent](h ttp://dev.classmethod.jp/cloud/scheduled_to_start_instance_from_lambda/)