こんばんは、cloudpack@dz_ こと大平かづみです。

Prologue – はじめに

友達から re:Invent のお土産でもらった AWS IoT ボタンを使って、 AWS Lambda 、しかも PHP を動かしてしまおうという小ネタです。

(PHP on AWS Lambda は、神宮前Geek Night!!のLTネタ探ししてるときに、「やってる人いるからできるよー」と、@yoshidashingo さんにそそのかされました(笑) でもいい経験になりました!ありがとうございます!)

ちなみに、 Lambda Advent Calendar に投稿しようと思ったのですがすでに満員だったので、 AWS IoT Advent Calendar 2015 に投稿してみました。小ネタですが済みません!

早速、準備

さっそく AWS IoT ボタン + PHP on AWS Lambda の環境を作っていきます。

  1. AWS IoT ボタンの準備(アクティベーション、サンプル動作確認)
  2. AWS Lambda で PHP を動かす ← 難関!!
  3. AWS IoT ボタンから PHP on AWS Lambda を起動!

AWS IoT ボタンの準備

今この時点で、すでに AWS IoT ボタンのアクティベーションとサンプルの動作は終わっています。手順にまとめようと思いましたが、あまりにも簡単ですし、他に情報がたくさんありますので、割愛します。

AWS IoT ボタンって?

念のため、AWS IoT ボタンについて軽く説明しておきます。

この AWS IoT ボタンは、デバイス固有のコードを書くことなく、AWS の IoT プラットフォームである AWS IoT を利用できる、ベータ版プロトタイプ端末です。

AWS IoT ボタンは、WiFi経由でインターネットに接続でき、初回は同梱されているアクティベーションコードとDSN(※)を入力して自身のAWSアカウントと紐づけます。(※ボタン端末の裏側に記載されている Device Serial Number)

WiFi接続や、アクティベーションとサンプルを動かすチュートリアルについては、「ご利用開始にあたって」を参照してみてください。

AWS Lambda で PHP を動かす

それでは、AWS Lambda で PHP を動かす準備に入ります。

ご存知の通り、AWS Lambda では、Node.js, Java, Python が動きます。だがしかし、 PHP はサポートされていません!

とはいえ、動いているのは Linux です。試しに、Lambda の動いている環境で uname -a を実行してみると、 Linux ip-10-0-74-236 3.14.48-33.39.amzn1.x86_64 #1 SMP Tue Jul 14 23:43:07 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux と返却されます。

また、Lambda は、単一のソースコードファイルだけでなく、zipにまとめてアップロードすることで、複数ファイルやディレクトリを含んだ環境を動かすこともできます。

これらの仕組みを利用して、 @yoshidashingo 氏から教えてもらったこちらの資料を参考に、Linuxで動作するPHPの実行ランタイムをアップロードして、Lambda でも PHP を動かしてしまおうという魂胆なのです!

PHPという概念が存在しない退屈な世界 from Yoshihiro Ohsuka

さて、ここで胆となるPHP実行ランタイムをどう入手するかというと、Lambda の環境で動くように、ビルドして作成しなければなりません。

  1. Linux 環境を用意する
  2. Lambda 環境で動く PHP をビルドする
  3. Lambda用のzipアーカイブを作成する
  4. Lambda にアップロードする

Linux環境を用意する

作業環境が Windows なので、別途 AWS EC2 で Linux 環境を作ります。手っ取り早く、Amazon Linux を利用しました。

Lambda環境で動く PHP をビルドする

Lambda のコードが配置されるディレクトリは、 /var/task です。なので、Linux 環境に /var/task を作成してそこで PHP が動くようにビルドします。

PHP のビルドについては、こちら「PHP 5.5.1をインストールする(ソースからビルドする方法)」を参考にしました。とても分かりやすかったです。

ちなみに、リリースされたばかりの PHP 7 で試してみました!

# Lambda の実行環境と同じディレクトリ構成を作成する
mkdir /var/task

# PHP配置用ディレクトリを作成する
mkdir /var/task/php

# ビルドに必要なパッケージをインストールする
yum install gcc
yum install make

# PHP のソースコードをダウンロードする
wget http://jp2.php.net/get/php-7.0.0.tar.gz/from/this/mirror -O php-7.0.0.tar.gz

# 展開して、展開先ディレクトリへ移動する
tar xfz php-7.0.0.tar.gz -C /usr/local/src/
cd /usr/local/src/php-7.0.0/

# ビルドファイルを作成する (インストール先は /var/task/php 、追加機能はすべて無効)
./configure --prefix=/var/task/php --disable-all

# ビルド
make

# インストール
make install

これで、 /var/task/php 配下に PHP 環境がインストールされました。

# インストールされた PHP ランタイム (※ tree コマンドで 3 階層まで表示)
 tree -L 3 /var/task
/var/task
└── php
    ├── bin
    │   ├── php
    │   ├── php-cgi
    │   ├── php-config
    │   ├── phpdbg
    │   └── phpize
    ├── include
    │   └── php
    ├── lib
    │   └── php
    ├── php
    │   └── man
    └── var
        ├── log
        └── run

Lambda 用のzipアーカイブを作成する

Lambda は、実行時の起点となるハンドラーを指定します。Node.js 版のハンドラーには通常 index.handler が指定されていて、これは index.jsexports.handler に登録された関数を実行するということです。今回の構成もこれに倣います。

index.js および PHP実行用のファイルを作成し、zipで固めます。

# Lambdaの疑似ディレクトリへ移動する
cd /var/task

# AWS Lambda 関数用のコードを作成する
vi index.js

# PHP 実行用のシェルスクリプトを作成する
vi run.sh

# 実行する PHP ファイルを作成する
vi info.php

# 各ファイル作成後の構成
tree -L 3 /var/task
/var/task
├── index.js
├── info.php
├── php
│   ├── bin
│   │   ├── php
│   │   ├── php-cgi
│   │   ├── php-config
│   │   ├── phpdbg
│   │   └── phpize
│   ├── include
│   │   └── php
│   ├── lib
│   │   └── php
│   ├── php
│   │   └── man
│   └── var
│       ├── log
│       └── run
└── run.sh

作成したファイルの内容はこちらです。

index.js

var exec = require('child_process').exec;

exports.handler = function(event, context) {
    var child = exec("sh ./run.sh", function(error) {
        // Resolve with result of process
        context.done(error, 'Process complete!');
    });

    // Log process stdout and stderr
    child.stdout.on('data', console.log);
    child.stderr.on('data', console.error);
};

run.sh

#!/bin/sh
./php/bin/php info.php

info.php


zipにまとめます。zipを回答したときに、直下に index.js が配置されるように zip 化してください。

# Lambda の疑似ディレクトリで、zip アーカイブを作成する
cd /var/task
zip -r task.zip .

この task.zip を手元にダウンロードし、Lambda にアップロードします。今回は 10KB 以上になってしまったので、S3経由でアップロードしました。

動作確認して問題なければ、次に進みましょう!

AWS IoT ボタンから PHP on AWS Lambda を起動!

それでは、AWS IoT ボタンの押下で PHP on Lambda が起動するように設定しましょう。

AWS IoT ボタンのサンプルを設定したあとは、Things,Roles,Certificates,Policiesが1個ずつ設定された状態になっています。

このうち、ルール を選択し、「Edit Actions」から「Add New Action」をクリックします。

3308c6b6-d8d2-a05e-1497-1c3134b38bb8

「Choose an action」で、「Insert this message into a code function and excute it (Lambda)」を指定します。

192e1fff-35bc-cf46-350b-e90071741a12

「Function Name」に、先ほど作ったLambda関数を指定します。

7373e882-f8d8-6265-3ac3-878c25226757

それでは!
AWS IoT ボタンを押してみます。

ポチっとな!

346609e8-6728-53fe-bf83-7f412e0591c0

CloudWatch を確認してみると…

a797824c-c6e6-68bc-303d-acfab22231d5

キターーー!ヾ(o´∀`o)ノ

Epilogue – おわりに

AWS IoT から Lambda を利用する方法もわかり、いろいろ勉強になりました。今回、一番難関と思っていた PHP のビルドですが、ちょっと師匠 @kazumihirose にアドバイスをいただきつつ手順に倣うとすんなりできました!

しかし、今回はわざわざ AWS IoT ボタンから PHP を動かしましたが、これ、特に何も役に立たないので、次はもっと役立ちそうなものを作りたいですね(笑)

元記事はこちら

Check! AWS IoT ボタンで PHP on AWS Lambda を動かす小ネタ