Edited at
ClojureDay 21

amazonicaとAWS Lambdaで定期的にEBSのスナップショットを作成する

More than 3 years have passed since last update.

この記事は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