SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

小規模な受託開発におけるAWS活用の勘所

受託開発でもサーバレスを活用しよう! Twilio、AWSを組み合わせたアプリケーション開発事例

小規模な受託開発におけるAWS活用の勘所 第4回

  • X ポスト
  • このエントリーをはてなブックマークに追加

実際にサーバレスアプリケーションを作ってみよう

 ここでは実際にサーバレスで構築したシステムを例に取り、構築方法をご紹介します。

 実際に手を動かすとメリットを感じやすいと思います。

 少し特異な例ですが、コンタクトセンターに掛かってきた電話(呼)が取り切れなかった際に応答する、IVR(Interactive Voice Response: 自動音声応答)システムの構築をサーバレスで行いました。

 このシステムを作成する方法をご紹介します。

サーバーレスアプリケーション用開発ツール

 AWS上にアプリケーションを構築する場合のツール選定はこちらを参照してください。

 今回は開発言語はPythonとし、フレームワークはZappaを使用します。

 Zappaは特にWSGI(Web Server Gateway Interface)を使用したWebアプリケーションを開発する際に非常にシンプルで素早く開発ができると思います。Pythonのみで完結する点も魅力です(ZappaはWebアプリケーション以外の用途でも利用可能です)。より複雑なアーキテクチャを組む場合は、Serverless Frameworkも検討してみてください。

今回使用する環境

 音声部分にはTwilioを、Twilioで使用されるAPIはAWSのAPI Gateway及びLambdaを使用します。

 事前にTwilioとAWSのアカウントの設定をし、以下を準備しておいてください。

TwilioとAWS
項目 内容 記事中での値
IAM CLI/SDKが使用可能で、AdministratorAccessポリシーが適用されたIAMユーザの作成 [profile]
twilio
DNS 独自ドメインの取得 test.com
DNS AWS Route53 ホストゾーンの設定、NSレコード設定 -
証明書 AWS Certificate Managerで*.ドメイン名の証明書を取得(CloudFrontで使用されるため、バージニア北部で取得する) [arn]
arn:aws:acm:us-east-1:XXXXXXX:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx
S3 デプロイ用S3バケットの作成 [バケット名]
develop-twilio.test.com

 IAMユーザーは作成したら、開発用PCの~/.aws/credentialsに以下のように設定してください。

~/.aws/credentials
[twilio]
aws_access_key_id = XXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXX

 また、開発はMacにて実施します。pyenvをインストールしておいてください。

サーバレスでアプリケーション構築

開発環境準備

 まず、Pythonによる開発環境を準備します。

 プロジェクト用ディレクトリで以下のコマンドを実行し、venvによる仮想環境を作成・有効化します。

 なお、執筆時点でLambdaでサポートされているPythonのランタイムは2.7もしくは3.6であるため、今回は3.6を使用します。

# Python 3.6.8のインストール
pyenv install 3.6.8
# pyenvにより、pythonのバージョンを3.6.8に
pyenv local 3.6.8
# venvというディレクトリに仮想環境を作成
python -m venv venv
# 仮想環境を有効化
venv/bin/activate

 次に、プロジェクトに必要なパッケージを仮想環境にインストールします。

# pipのバージョンアップ
(venv)$ pip install --upgrade pip
# Webアプリケーションフレームワークとしてflaskを使用
(venv)$ pip install flask
# サーバーレスフレームワークとしてzappaを使用
(venv)$ pip install zappa
# twilio用SDK
(venv)$ pip install twilio
# パッケージ管理
(venv)$ pip freeze > requirements.txt

 以上で準備は完了です。

APIの実装

 ここからAPIを実装します。といっても、通常のWebアプリケーションと内容は全く変わりません。

 ここでは、Twilio Programmable Voiceを使用して、簡単なText to Speechを実装します。

run.py
import os
from flask import Flask, request
from werkzeug.exceptions import Forbidden
from typing import Callable
from functools import wraps
from twilio.request_validator import RequestValidator
from twilio.twiml.voice_response import VoiceResponse

# flask初期化
app = Flask(__name__)


def get_app_env() -> str:
    """
    環境変数APP_ENVの取得
    """

    app_env = os.environ.get('APP_ENV')

    if app_env is None:
        app_env = 'local'

    return app_env


def validate_twilio_request(f: Callable) -> Callable:
    """
    Twilioからのリクエストであることを認証
    """

    @wraps(f)
    def decorated_function(*args, **kwargs) -> Callable:
        # 開発環境は認証をしない
        if get_app_env() == 'local' or get_app_env() == 'develop':
            return f(*args, **kwargs)

        # 環境変数に設定されているTWILIO_AUTH_TOKENを使用してバリデーション実施
        validator = RequestValidator(os.environ.get('TWILIO_AUTH_TOKEN'))
        request_valid = validator.validate(
            request.url,
            request.form,
            request.headers.get('X-TWILIO-SIGNATURE', '')
        )

        if request_valid:
            return f(*args, **kwargs)
        else:
            raise Forbidden
    return decorated_function


@app.route('/api/init', methods=['POST'])
@validate_twilio_request
def twilio_init() -> str:
    """
    コールがあった際、最初にhookされるAPI
    発番号を取得し、発声する
    """

    response = VoiceResponse()

    # 発番の取得
    caller_id = request.form['Caller']

    # Aliceに話をさせる。
    response.say(caller_id + 'からのお電話を頂いています。', voice='alice', language='ja-JP')

    # 次のAPIへリダイレクト(実際は条件分岐に基づき、リダイレクトされる)
    response.redirect('/api/next')

    return str(response)


@app.route('/api/next', methods=['POST'])
@validate_twilio_request
def twilio_next() -> str:
    """次に呼ばれるAPI"""

    response = VoiceResponse()
    # Aliceに話をさせる。
    response.say('では、さようなら。', voice='alice', language='ja-JP')
    # 1秒待って
    response.pause()
    # 呼を切断
    response.hangup()

    return str(response)


if __name__ == '__main__':
    app.run(debug=True)

 Twilioで取得した電話番号に電話が架電されると、/api/initに POSTさせます。/api/initでは発信者番号を取得して、電話番号をオウム返ししています。その後、/api/nextへリダイレクト(301/302ではなく、Twilioが音声を発し終わったら、/api/nextPOSTさせる)させ、呼を切断する、という動作を実装しています。

AWSへデプロイ

 AWSへデプロイする前に、AWSへどのような環境でデプロイするのか設定を記述する必要があります。Zappaではzappa_settings.jsonもしくはzappa_settings.ymlに設定を記載します。

 以下ではdevelopというステージでデプロイしています。

zappa_settings.json
{
    "develop": {
        "domain": "develop-twilio.test.com",
        "apigateway_enabled": true,
        "certificate_arn": "arn:aws:acm:us-east-1:XXXXXXX:certificate/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx",
        "app_function": "run.app",
        "keep_warm": true,
        "profile_name": "twilio",
        "s3_bucket": "develop-twilio.test.com",
        "aws_environment_variables": {
            "APP_ENV": "develop",
            "TWILIO_AUTH_TOKEN": "xxxxxxxxxxxxxxxx",
            "TZ": "Asia/Tokyo"
        },
        "runtime": "python3.6",
        "aws_region": "ap-northeast-1",
        "log_level": "DEBUG",
        "memory_size": 256,
        "timeout_seconds": 30
    }
}

 各項目の意味は想像がつくものが多いと思いますが、詳細はこちらを参照してください。

 aws_environment_variablesに設定しているTWILIO_AUTH_TOKENはTwilioの画面から取得してください。

Twilio APIクレデンシャル AUTH TOKEN
Twilio APIクレデンシャル AUTH TOKEN

 では、実際にデプロイします。

(venv) $ zappa deploy develop
...
Deployment complete!: https://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/develop

 メッセージを見ると分かりますが、IAMユーザーが作成されたり、S3にファイルがアップロードされたり、API Gatewayがデプロイされたりしています。実施はS3にファイルがアップロードされ、CloudFormationを通じて各サービスがデプロイされています。

 ここまでで、API Gatewayまではデプロイされました。コマンドの最後に出力されているhttps://xxxxxx.execute-api.ap-northeast-1.amazonaws.com/developは実際に可動するURLで、独自ドメイン(カスタムドメイン)を設定しない場合、https://APIゲートウェイのFQDN/ステージというURLになります。

 次に、カスタムドメインの設定をします。

(venv) $ zappa certify develop --yes
...
Created a new domain name with supplied certificate. Please note that it can take up to 40 minutes for this domain to be created and propagated through AWS, but it requires no further work on your part.
Certificate updated!
(venv) $

 これでRoute53に(内部的に使用されている)CloudFrontディストリビューションのCNAMEレコードが作成され、しばらくするとhttps://develop-twilio.test.com/api/init等にアクセスできるようになります。

Twilioの設定

 次にTwilioの設定をします。

 Programmable Voiceの画面から電話番号を購入します。

電話番号の購入1
電話番号の購入1
電話番号の購入2
電話番号の購入2

 購入した電話番号のWebhookを設定します。

 Programmable Voiceの画面から電話番号に対する設定をします。

電話番号へのWebhookの設定1
電話番号へのWebhookの設定1

 先程購入した電話番号をクリックします。

電話番号へのWebhookの設定2
電話番号へのWebhookの設定2

 音声およびFaxの通話着信時の動作をWebhookで、URLをhttps://develop-twilio.test.com/api/init、メソッドはHTTP POSTを設定し、保存します。

電話番号へのWebhookの設定3
電話番号へのWebhookの設定3

 これで設定は完了です。購入した050番号に電話をすると、Lambdaで実装した自動音声が流れます。

最後に

 小規模な業務システム開発におけるサーバレスアーキテクチャの使い所と実例について説明させていただきました。文中で触れた用途以外にも、発想しだいで様々な用途が考えられると思います。うまく活用することで、スピーディーでマネージドサービスの恩恵を享受できる開発に繋がると思います。

 サーバレスは「まずやってみる」ということが非常に大事だと思います。やってみることでイメージがつかめると発想の幅が大きく広がると思いますので、是非ご活用頂けますと幸いです。

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
小規模な受託開発におけるAWS活用の勘所連載記事一覧

もっと読む

この記事の著者

塩飽 展弘(株式会社鈴木商店)(シワク ノブヒロ)

 株式会社鈴木商店 経営企画室室長。 大手通信事業者にて、SE、研究開発、経営企画等に従事後、2016年株式会社鈴木商店に入社。 営業、要件定義、開発(主にAWS関連インフラ)に従事後、現職。 AWS Certified Solutions Architect - Professional 鈴木商店HP Facebook

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/11517 2019/05/16 11:00

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング