Lambda で実行したい外部コマンドがある場合バイナリをパッケージに含めるとデプロイに時間がかかってしまう。
package main
import (
"fmt"
"os/exec"
"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)
func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
cmd := exec.Command("git", "clone", "https://github.com/sambaiz/foobar.git", "/tmp/repo")
output, err := cmd.CombinedOutput()
if err != nil {
return events.APIGatewayProxyResponse{
Body: fmt.Sprintf("%s %s", string(output), err.Error()),
StatusCode: 500,
}, nil
}
return events.APIGatewayProxyResponse{
Body: string(output),
StatusCode: 200,
}, nil
}
func main() {
lambda.Start(handler)
}
exec: "git": executable file not found in $PATH
Lambda Layerを使うとライブラリやバイナリを切り出すことができ、複数Functionで共有することもできる。 ディレクトリを zip に固めて Layer に指定すると中身が /opt に展開され、/opt/bin には PATH が、/opt/lib はLD_LIBRARY_PATHが通るほか言語ごとのパッケージ置き場にもなる。
$ tree layer/
layer/
└── bin
└── some-command
zip は S3 に上げておくこともできるが、SAMでは AWS::Lambda::LayerVersion の ContentUri でローカルのパスを指定することもでき、sam local でも適用される。そうする場合 package するのにAWS CLIのバージョンが1.16.67以降である必要がある。
AWS SAMでLambdaの関数をデプロイしServerless Application Repositoryに公開する - sambaiz-net
$ cat template.yaml
...
Resources:
HelloWorldFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: hello-world/
Handler: hello-world
Runtime: go1.x
Layers:
- !Ref ExampleLayer
Events:
CatchAll:
Type: Api
Properties:
Path: /hello
Method: GET
ExampleLayer:
Type: AWS::Serverless::LayerVersion
Properties:
LayerName: SomeCommandLayer
Description: some-command binary is included
ContentUri: './layer'
CompatibleRuntimes:
- go1.x
RetentionPolicy: Delete
ということで lambci/git-lambda-layerを入れて git を使えるようにしようと思ったが、調べているうちに src-d/go-git を見つけたのでこちらを使うことにした。
_, err := git.PlainClone("/tmp/repo", false, &git.CloneOptions{
URL: "https://github.com/sambaiz/foobar.git",
Progress: os.Stdout,
})