手を動かしながら学ぶサーバーレスハンズオンをやってみた

初めに

私が、AWSを学習したudemyの講座の講師をされていた
金澤さんのハンズオンだったので、凄く楽しみにしていたのですが、
ハンズオンに行けなかったため自己学習です。

本記事は、以下の勉強会で実施された内容です。

https://jawsug-bgnr.connpass.com/event/165065/

"サーバーレス"とは何か?何がうれしいのか?

開発者がやりたいこととやらなければいこと

  • 開発者やりたいこと

    • ユーザーに価値を届ける
  • やるべきこともたくさん

サーバーレスでは、サーバの管理が不要なため、
開発者はユーザーに価値を届けることに集中できる!

サーバーレスアーキテクチャの特徴

  • インフラのプロビジョニングや管理が不要
  • ビルドインの高可用性
  • 自動でスケール
  • 価値に対する支払い

AWS Lamdbaで 日→英 翻訳します

シナリオ#1 日→英翻訳をすぐさまやりたい

  • オリンピックのある今年は英語を使う機会も多い
  • 英語の聞き取りは大丈夫、でも喋るのが。。
  • でもいつその機会に遭遇するかはわからない
  • コストは少しでも押さえたい

AWSにおけるComputeサービス

  • EC2
    • 自由度:高い
    • 管理の手間:多い
  • Lambda
    • 自由度:低い
    • 管理の手間:少ない

AWS Lambdaの特徴

  • サーバーのプロビジョニング/管理なしで、プログラムを実行できるサービス
  • コードを実行するための準備、スケーリングなどは、Lambda側で実施
    開発者の方はコードを書くことに集中できる
  • 料金体系はリクエストベース
    • 実行回数 + 実行時間(単価は確保したメモリ量)
      ※無料枠あり

ハンズオン

AWS Lambdaを用い、下記の2つの作業を進めていく

  1. Lambda Functionを作成し、"Hello World"と表示します
  2. Lambda Functionを修正し、Amazon Translateと連携します

Lambda Functionを作成し、"Hello World"と表示します

  1. IAMユーザでログイン&初期設定

    • 右上:東京リージョンを選択
    • 画面左下のEnglish(US)日本語に変更 f:id:Tk24:20200220183744j:plain
  2. AWS Lambda画面へ

    • サービス検索窓にLambdaと入力し、下に出てくるLambdaをクリックします f:id:Tk24:20200220183831j:plain
  3. Lambda Functionの作成

    • 右上の橙色の関数の作成をクリックします f:id:Tk24:20200220183901j:plain

    • 一から作成のままでOK

    • 関数の情報を入力し、右下の関数の作成をクリックします

      • 関数名:translate-function
      • ランタイム:Python3.8 f:id:Tk24:20200220183917j:plain
    • 少し下にスクロールするとソースコードが見えてくる

    • 7行目の"Hello from Lambda!"の中身を何でも良いので修正します
    • 右上の保存ボタンをクリックします f:id:Tk24:20200220184020j:plain
  4. Lambda Functionをテスト実行します

    • 右上のテストをクリックします
    • イベント名にTestと入力します f:id:Tk24:20200220184154j:plain
    • 右下の作成ボタンをクリックします f:id:Tk24:20200220184205j:plain
    • 右上のテストボタンをクリックします
    • statusCode: 200,が表示されれば成功です f:id:Tk24:20200220184236j:plain

Lambda Functionを修正し、Amazon Translateと連携します

  1. Lambda Function のIAMロールを修正します
    • Lambda Function 画面の下の方にスクロールしてください
    • xxx ロール表示しますをクリックします f:id:Tk24:20200220184427j:plain

    • ポリシーをアタッチしますをクリックします f:id:Tk24:20200220184447j:plain

    • 検索窓にtranslateと入力し、
      TranslateFullAccessの方にチェックを入れます f:id:Tk24:20200220184511j:plain
    • その後、右下のポリシーのアタッチをクリックします
    • Lambda画面に戻ります
  2. Lambda Functionのソースコードを修正
    • 以下のようにソースコードを修正します 1 ・"AWS SDK Python"と検索するとリファレンスが出てくるので、それをみながら開発を進めます
import json
import boto3

def lambda_handler(event, context):

  translate = boto3.client('translate')
  input_text = '順調ですか?'
  response = translate.translate_text(
    Text=input_text,
    SourceLanguageCode='ja',
    TargetLanguageCode='en'
  )

  output_text = response.get('TranslatedText')

  return {
    'statusCode': 200,
    'body': json.dumps({
      'output_text': output_text
    })
  }
  • 保存 > テストをクリックします
    • 翻訳結果が出ていればOKです
      input_test の文字列を変更し、色々試してください

翻訳 Web APIを作る

シナリオ#2 日→英 翻訳をWeb API化したい

  • 翻訳したいときに常にマネージメントコンソールにログインできるとは限らない
  • スマホからでもサクッと接続できるようにWeb API 化したい
  • いつでも使えないと困るけど、冗長性のための設計はしている時間がない...

サーバーレスアーキテクチャでよく利用されるAWSサービス

Amazon API Gatewayの特徴

  • サーバーのプロビジョニングや管理無しで、APIを作成・管理できるマネージドサービス
  • 可用性の担保、スケーリングなどのAPI管理で必要なことをAPI Gatewayに任せる事で、開発者はビジネスの差別化につながる作業に集中できます
  • 料金体系はリクエストベース(※REST APIの場合)

ハンズオン

Amazon API GatewayAWS lambdaを組み合わせて、外部から叩けるWeb APIを作って行きます。

  1. Lambda Functionのソースを修正
    • input_text の部分をAPI Gatewayから渡される、クエリストリンクパラメータを受け取る形に修正し、保存します
import json
import boto3

def lambda_handler(event, context):
  translate = boto3.client('translate')

  input_text = event['queryStringParameters']['input_text']

  response = translate.translate_text(
    Text=input_text,
    SourceLanguageCode="ja",
    TargetLanguageCode="en"
  )
...
  1. API Gateway - APIの作成

    • "Amazon API Gateway"画面に遷移
      右上のサービス > 検索窓にapiと入力 > API Gatewayを選択
    • 右上のAPIを作成を押してください2
    • 下部に遷移し、REST API構築ボタンをクリックします3
      f:id:Tk24:20200220184730j:plain
    • プロトコルRESTのまま、そのしたで新しいAPIを選択します
    • API名をtranslate-apiとし、右下のAPIを作成をクリックします f:id:Tk24:20200220184850j:plain
  2. API Gateway - リソースの作成

    • アクション > リソースの作成をクリックします f:id:Tk24:20200220184936j:plain
    • "リソース名"をtranslateとし、リソースの作成をクリックします f:id:Tk24:20200220185002j:plain
  3. API Gateway - メソッドの作成

    • /translateが選ばれている状態で、アクション > メソッドの作成をクリックします
    • "/translate"の下のプルダウンから、GETを選択し、チェックマークをクリックします f:id:Tk24:20200220185031j:plain
    • Lambdaプロキシ統合の使用チェックしたのち、
      "Lambda 関数"にtranslate-functionを指定し、保存をクリックします f:id:Tk24:20200220185107j:plain
    • "Lambda 関数に権限を追加する"ダイアログで、OKをクリックします
  4. API Gateway - デプロイ

    • アクションからAPIのデプロイを実施 f:id:Tk24:20200220185136j:plain

    • 初めてのデプロイなので、ステージを作成します
      新しいステージを選択し、ステージ名にdevと入力し、デプロイをクリックします f:id:Tk24:20200220185157j:plain

    • 左側のメニューでステージが選ばれていることを確認します4

    • URLが生成されるので、コピーし、ブラウザに貼り付けます

    • 貼り付けたURLの後ろに、/translate?input_text=初めてのAPI呼び出しですを付けます

    • これで、翻訳API完成です
      好きな言葉を入れて試してみてください

文字起こし + 翻訳パイプラインを作る

シナリオ#3 英文の文字起こしをしたい

  • さっき聞き取りは問題ないといったけど、嘘でした...
  • 喋ってもらった内容をテキスト化できないと辞書も引けない
  • まず文字お越しするところだけでも自動化できないだろうか

Amazon Transcribeの特徴

  • 音声をテキストにする文字お越しサービス
    • 2019年11月に日本語対応
    • 保存した音声ファイルやリアルタイム変換が可能 5

Amazon Simple Storage Service(Amazon S3)の特徴

  • 高い耐久性を持つオブジェクトストレージサービス
    • 99.999999999%(イレブンナイン)
    • 標準で少なくとも3つのAZに格納されている
  • 容量無制限、安価なストレージ
  • 様々なAWSサービスと連携
    • 例:ファイルが格納されたことをトリガーに非同期にLambda関数を呼ぶ

ハンズオン

AWS LambdaとAmazon Transcribeを組み合わせて、音声データを文字お越しするパイプラインを作ります

1.S3のバケットを作成する

  • input用とoutput用に2つのS3バケットを作成します
  • サービス > S3と入力 > S3を選択
  • バケットを作成するをクリックします
  • バケット名をyyymmdd-transcribe-input-yournameとする6 リージョンは、lambdaと同じにしてください

f:id:Tk24:20200220185704j:plain

  • 左下の作成ボタンをクリックします
  • 2つ目のバケットも作成します
  • バケット名をyyymmdd-transcribe-output-yournameとする
  • 左下の作成ボタンをクリックします

2.Lambda Functionの作成

  • AWS Lambdaの画面へ:サービス > lambdaと入力 > Lambdaを選択します
  • 関数の作成をクリックします
  • 設計図の使用 > 検索窓にS3と入力し、Enter f:id:Tk24:20200220191737j:plain
  • s3-get-object-pythonを選択し、右下の設定をクリックします f:id:Tk24:20200220192107j:plain
  • Function名:transcribe-function,
    Role 名:transcribe-function-roleとし、下へ移動します
  • S3 トリガーの対象になるinput用のバケットを指定します
  • トリガーの有効化チェックをつけます f:id:Tk24:20200220192142j:plain
  • 下部の関数の作成をクリックします
  • IAM ロールを修正する
    Lambda Functionの下部からxxx ロールを表示をクリックします
  • ポリシーをアタッチしますをクリックします
  • 検索窓にS3と入力 > AmazonS3FullAccessにチェックします
  • 検索窓をクリアし、transcribeと入力 > AmazonTranscribeFullAccessにチェックします
  • ソースコードを以下のように修正し、保存する
    • OutputBucketNameにはOutputバケット名を入力してください
import json
import urllib.parse
import boto3
import datetime

s3 = boto3.client('s3')
transcribe = boto3.client('transcribe')

def lambda_handler(event, context):
  bucket = event['Records'][0]['s3']['bucket']['name']
  key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf-8')
  try:
    transcribe.start_transcription_job(
      TranscriptionJobName= datetime.datetime.now().strftime("%Y%m%d%H%M%S") + '_Transcription',
      LanguageCode='en-US',
      Media={
        'MediaFileUri': 'https://s3.ap-northeast-1.amazonaws.com/' + bucket + '/' + key
      },
      OutputBucketName='YYYYMMDD-transcribe-output-YourName'
    )
  except Exception as e:
    print(e)
    print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
    raise e

3.パイプラインのテストを実施する

  • 音声ファイルは下記URL(Amazon Pollyのサンプル)から、ダウンロードします

https://d1.awsstatic.com/product-marketing/Polly/HelloEnglish-Joanna.0aa7a6dc7f1de9ac48769f366c6f447f9051db57.mp3

  • S3にmp3ファイルをアップロードする
    input側のS3バケットアップロードをクリックします

  • ファイルを追加から先ほどDLしたmp3ファイルを指定し、アップロードします

  • サービス > transcribeと入力 > Amazon Trabscribeを選択します

  • 左上のハンバーガーメニューをクリックし > Transcription Jobsをクリックします

  • Job StatusがIn progressであることを確認し、Completeになるまで待ちます f:id:Tk24:20200220192248j:plain

  • Jobが完了したら、Output側のS3を確認します
    yyyymmddhhmmss_Transcription.jsonファイルがあれば成功です f:id:Tk24:20200220192322j:plain

  • Jsonファイルの中の resulte > transcripts > transcriptを確認します
    “transcript”: “Hello. Do you speak a foreign language? One language is never enough.”と文字起こしされていると思います。 {"jobName":"20200220074630_Transcription","accountId":"XXXXXXXXXXXX","results":{"transcripts":[{"transcript":"Hello. Do you speak a foreign language? One language is never enough."}],"items":[{"start_time":"0.04","end_time":"0.65","alternatives":[{"confidence":"0.9139","content":"Hello"}],"type":"pronunciation"},{"alternatives":[{"confidence":"0.0","content":"."}],"type":"punctuation"},{"start_time":"1.04","end_time":"1.14","alternatives":[{"confidence":"1.0","content":"Do"}],"type":"pronunciation"},{"start_time":"1.14","end_time":"1.27","alternatives":[{"confidence":"1.0","content":"you"}],"type":"pronunciation"},{"start_time":"1.27","end_time":"1.59","alternatives":[{"confidence":"1.0","content":"speak"}],"type":"pronunciation"},{"start_time":"1.59","end_time":"1.65","alternatives":[{"confidence":"0.9991","content":"a"}],"type":"pronunciation"},{"start_time":"1.65","end_time":"1.99","alternatives":[{"confidence":"1.0","content":"foreign"}],"type":"pronunciation"},{"start_time":"1.99","end_time":"2.59","alternatives":[{"confidence":"1.0","content":"language"}],"type":"pronunciation"},{"alternatives":[{"confidence":"0.0","content":"?"}],"type":"punctuation"},{"start_time":"2.88","end_time":"3.19","alternatives":[{"confidence":"0.9944","content":"One"}],"type":"pronunciation"},{"start_time":"3.19","end_time":"3.61","alternatives":[{"confidence":"0.991","content":"language"}],"type":"pronunciation"},{"start_time":"3.61","end_time":"3.75","alternatives":[{"confidence":"0.991","content":"is"}],"type":"pronunciation"},{"start_time":"3.75","end_time":"4.03","alternatives":[{"confidence":"1.0","content":"never"}],"type":"pronunciation"},{"start_time":"4.03","end_time":"4.48","alternatives":[{"confidence":"0.9079","content":"enough"}],"type":"pronunciation"},{"alternatives":[{"confidence":"0.0","content":"."}],"type":"punctuation"}]},"status":"COMPLETED"}

まとめ

ハンズオン資料がかなりしっかりしていたため、
特に困ることなく構築できました。 順序だてて丁寧に説明があるので、非常にわかりやすかったです。

こんな簡単に、システムを作れるとは面白いですね。 宿題 や +α があるので構築しようと思います。


  1. AWS SDK for Python(boto3)を利用します

  2. 既存のAPIがある場合のみ、ない場合は次の手順へ

  3. もし、"最初にAPIを作成する"ポップアップが出てきたらOKをクリックします

  4. 選ばれていなければステージを選択>devをクリック

  5. ただし、リアルタイム変換は日本語未対応

  6. バケット名は世界中でユニークにする必要があります