【小ネタ】簡単にLambda関数のコンテナ内でコマンドを実行する方法

2016.07.28

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは、中山です。

先程ネットサーフィン(死語)していたところ面白そうなツールを見つけました。作者はLambda関数のデプロイツールApexを作成した方です。

このツールを使うとLambda関数のコンテナ内でシェルを起動させ、コマンドを実行できます。普段はあまり意識することのないLambda関数のコンテナの内部を垣間見えたのでレポートします。

インストール方法

READMEに書いてあるとおり go get コマンドでインストール可能です。

$ go get github.com/apex/apex-shell

以下のコマンドを実行してインストールされたことを確認してください。

$ apex-shell -version
1.0.0

環境によって異なりますが、失敗するかと思います。例えば以下のように「XXがない」と言われたら、おとなしくそのパッケージを go get でインストールしてください。

$ apex-shell -version
FATAL[0000] error: build hook: main.go:8:2: cannot find package "github.com/apex/go-apex" in any of:
        /usr/local/Cellar/go/1.6/libexec/src/github.com/apex/go-apex (from $GOROOT)
        /Users/knakayama/.go/src/github.com/apex/go-apex (from $GOPATH)
/Users/knakayama/.go/src/github.com/apex/log/handlers/logfmt/logfmt.go:10:2: cannot find package "github.com/go-logfmt/logfmt" in any of:
        /usr/local/Cellar/go/1.6/libexec/src/github.com/go-logfmt/logfmt (from $GOROOT)
        /Users/knakayama/.go/src/github.com/go-logfmt/logfmt (from $GOPATH)
$ go get github.com/apex/go-apex

最終的にバージョン番号が表示されたらインストール完了です。

下準備

apex-shell は Apex のプロジェクト上で実行させる必要があります。 project.json からさまざまな情報を取得しているためです。そのため一度プロジェクトを作成する必要があります。作成方法は以下のとおりです。入力する <project-name><project-description> は適当なものを入力してください。

$ apex init


             _    ____  _______  __
            / \  |  _ \| ____\ \/ /
           / _ \ | |_) |  _|  \  /
          / ___ \|  __/| |___ /  \
         /_/   \_\_|   |_____/_/\_\



  Enter the name of your project. It should be machine-friendly, as this
  is used to prefix your functions in Lambda.

    Project name: <project-name>

  Enter an optional description of your project.

    Project description: <project-description>

  [+] creating IAM test_lambda_function role
  [+] creating IAM test_lambda_logs policy
  [+] attaching policy to lambda_function role.
  [+] creating ./project.json
  [+] creating ./functions

  Setup complete, deploy those functions!

    $ apex deploy

Apexのインストール方法は以下のエントリを参照してください。

正常にプロジェクトが作成されると以下のようにファイルとLambda関数用IAM Roleが作成されます。

$ tree .
.
├── functions
│   └── hello
│       └── index.js
└── project.json

2 directories, 2 files

コンテナ内に突入

準備が整ったのでいよいよ apex-shell コマンドを実行してみましょう。

$ apex-shell
  INFO[0004] creating function         env= function=repl
  INFO[0007] created alias current     env= function=repl version=3
  INFO[0007] function created          env= function=repl name=test_repl version=3
apex>

apex-shell と入力するとREPL用のLambda関数が起動し、シェルが立ち上がります。続いて、適当にコマンドを実行してみましょう。

apex> whoami
sbx_user1053
apex> pwd
/var/task
apex> ls -l
total 3236
-rw-rw-r-- 1 slicer 497     185 Jan  1  2098 _apex_index.js
-rw-rw-r-- 1 slicer 497    4710 Jan  1  2098 byline.js
-rw-rw-r-- 1 slicer 497     837 Jan  1  2098 index.js
-rwxr-xr-x 1 slicer 497 3293168 Jan  1  2098 main
-rwxr-xr-x 1 slicer 497     624 Jan  1  2098 main.go

コンテナ内で利用可能なコマンドは実行可能なようです。当たり前ですが。

以前AWS Lambdaをいろいろ暴くという記事が一部界隈で話題になっていました。このときはLambda関数内で子プロセスを起動させコマンドを実行する、という方法でコンテナ内を調査していました。今回はREPL形式でコマンドを実行できるので、連続してコマンドを実行可能です。Lambda関数のコンテナを調べたい場合に捗るかもしれません。まぁあまりないかもしれませんが。

お遊びが終わったら先程作成したIAM Roleを削除しておきましょう。

どうやって動作しているのか

apex-shell のソースコードは200行程度です。覗いてみるとforループでLambda関数を起動させていることが確認できます。つまり、ローカルPCで入力したコマンドをLambda関数に渡して起動し、そのコマンドを実行、最終的に結果をローカルに表示させるという結構原始的な仕組みになっているようです。なので、実行内容的には先のリンク先と同じです。

まとめ

いかがだったでしょうか。

個人的には面白いツールを発見した感があります。普段意識してなかったものに触れられたのでそこそこ楽しめました。

本エントリがみなさんの参考になれば幸いです。