先日の記事で、大きめの処理をLambda+CloudFormationで実行するめどがついたので、S3+Lambda+CloudFormationでサーバレスyumリポジトリを作ってみた。
処理の概要
- S3にrpmを追加・更新・削除
- Lambdaがイベントをフック→cfnスタックを作成
- cfnスタックがEC2インスタンスを起動→S3リポジトリをダウンロード
- createrepoを実行して、インデックスをS3にアップロード
- cfnスタックは処理完了後に自動的に削除
Lambda Function
こんな感じ。
var Promise = require('bluebird'); var AWS = require("aws-sdk"); AWS.config.update({region: 'ap-northeast-1'}); var cloudformation = Promise.promisifyAll(new AWS.CloudFormation()); var fs = Promise.promisifyAll(require('fs')); exports.handler = function(event, context) { var stackName = 'my-stack-' + new Date().getTime(); fs.readFileAsync('template.json', 'utf8').then(function(data) { return cloudformation.createStackAsync({ StackName: stackName, Parameters: [ { ParameterKey: 'S3Bucket', ParameterValue: 'my-yum-repo' } ], TemplateBody: data }); }).then(function(data) { console.log(data); }).then(function() { context.succeed('OK'); }).catch(function(err) { context.fail(err); }); };
roleにはcfnスタックを作成できる適切な権限を付与しておく。
また、S3のイベントソースをPost/Put/Deleteで追加する。
なんか、イベントソースの情報取得まわりがぶっ壊れているような気が… 一応、動作はしました。
cfn template
こんな感じ。
{ "Parameters": { "S3Bucket": { "Type": "String" } }, "Resources": { "MyInstance": { "Type": "AWS::EC2::Instance", "Properties": { "ImageId": "ami-cbf90ecb", "InstanceType": "t2.micro", "SubnetId": "subnet-XXXXXXXX", "IamInstanceProfile": "my_role", "Tags": [ { "Key": "Name", "Value": {"Ref": "AWS::StackId"} } ], "UserData": { "Fn::Base64": { "Fn::Join": [ "", [ "#!/bin/bash\n", "yum install -y createrepo\n", "aws s3 sync s3://", {"Ref": "S3Bucket"}, " myrepo --delete\n", "createrepo myrepo\n", "aws s3 sync myrepo s3://", {"Ref": "S3Bucket"}, " --delete\n", "aws cloudformation delete-stack --stack-name ", {"Ref": "AWS::StackName"}, " --region ", {"Ref": "AWS::Region"}, "\n" ] ] } } } } } }
やってることは、まあ見たとおりです。
S3のバケットの構成
s3://my-yum-repo/ ├── noarch │ └── hello-0.1.0-1.noarch.rpm └── repodata ├── ... └── repomd.xml
yumの設定ファイル
/etc/yum.repos.d/my.repo
[my] name=my baseurl=http://my-yum-repo.s3-website-ap-northeast-1.amazonaws.com/ gpgcheck=0 enabled=1
使ってみる
初期状態でhello2というrpmはなし。
$ sudo yum clean all; sudo yum search hello2 ... 警告: 一致するものが見つかりません: hello2 見つかりませんでした
rpmファイルをS3においてみる。
$ aws s3 cp hello2-0.1.0-1.noarch.rpm s3://my-yum-repo/noarch/ upload: rpmbuild/RPMS/noarch/hello2-0.1.0-1.noarch.rpm to s3://my-yum-repo/noarch/hello2-0.1.0-1.noarch.rpm
すると、Lambdaが起動。
START RequestId: 3043f34d-3d9c-11e5-8a8b-ebe5957bb289 2015-08-08T07:07:55.968Z 3043f34d-3d9c-11e5-8a8b-ebe5957bb289 { ResponseMetadata: { RequestId: '30fc94cc-3d9c-11e5-8ca5-3128034c20e8' }, StackId: 'arn:aws:cloudformation:ap-northeast-1:123456789012:stack/my-stack-1439017674468/31109130-3d9c-11e5-8e97-5001aba754a8' } END RequestId: 3043f34d-3d9c-11e5-8a8b-ebe5957bb289 REPORT RequestId: 3043f34d-3d9c-11e5-8a8b-ebe5957bb289 Duration: 1558.67 ms Billed Duration: 1600 ms Memory Size: 128 MB Max Memory Used: 16 MB
Lambdaがcfnスタックを作成→EC2インスタンス起動。
EC2インスタンスでリポジトリのインデックスを更新→S3にアップロード。
EC2インスタンスは自動的に削除。
$ sudo yum clean all; sudo yum search hello2読み込んだプラグイン:fastestmirror ... ======================================= N/S Matched: hello2 ======================================== hello2.noarch : hello2