LoginSignup
6
4

More than 3 years have passed since last update.

AWSを利用したサーバーレスWebAPI開発環境の構築(zappaでAWSLambdaにデプロイする)

Last updated at Posted at 2020-05-24

概要

AWSを利用してシンプルなサーバーレスWebAPIを作成します:fist:
※大雑把に構築の流れだけ追っていくので、細かいことは都度調べてください:joy_cat:

目次

  1. ローカルで仮想環境の構築(キーワード:pipenv)
  2. 開発環境の構築(VSCode)
  3. プログラムの作成(Flask)
  4. IAMユーザーの作成(AWS)
  5. ローカル環境をAWSにデプロイ(zappa)
  6. おまけ
  7. 参考サイト

ローカルで仮想環境の構築(pipenv)

pipenvを使用して仮想環境を構築します。

:slight_smile: 環境変数に以下を追加します。
仮想環境で使用するインタープリターや参照パッケージを、作業フォルダに入れる設定です。(.venv)

PIPENV_VENV_IN_PROJECT = TRUE

:slight_smile: pipenvをインストールします。
コマンドラインで以下を実行します。

pip install pipenv

バージョンが表示されればインストールできています。

pipenv --version

:slight_smile: 作業フォルダを作成して、初期化を行います。
コマンドラインで作成した作業フォルダに移動して、以下を実行します。

pipenv --three

「three」はpython3系のインストールコマンドです。バージョンを指定する場合は、以下のように実行します。:thinking:

pipenv --python 3.7

初期化に成功すると、作業フォルダに以下のフォルダとファイルが作成されます。
.venv
Pipfile

開発環境の構築(VSCode)

VSCodeで開発環境を構築します。(VSCodeは良いぞ...:relieved:

:slight_smile: VSCodeで作業フォルダを開きます。
「ファイル」→「フォルダーを開く」
無題.png
VSCodeは、pythonファイルを扱えるようにするために、拡張機能を入れる必要があります。:thinking:
「表示」→「拡張機能」から「python」で検索してインストールしましょう。

:slight_smile: pythonファイルを作成します。
テキトーに「app.py」などのファイルを作成します。作成したpythonファイルを選択すると、エディターの左下に実行する環境が表示されます。
ここから、作業フォルダのpipenvを指定します。
無題2.png
:slight_smile: 設定ファイルを編集します。
以下のファイルで、仮想環境等のパス設定、フォーマッター、Lintの設定を行います。参考
無題3.png

[ワークスペースフォルダ]\.vscode\settings.json
{
    "python.pythonPath": "[ワークスペースフォルダ]\\.venv\\Scripts\\python.exe",

    // 拡張機能のロード時にターミナルでPython環境をアクティブにする。
    "python.terminal.activateEnvInCurrentTerminal": true,
    // 仮想環境のパス。作成した仮想環境を指定する。
    "python.venvPath": "{$workspaceFolder}/.venv",
    "python.autoComplete.extraPaths": [
        "{$workspaceFolder}/.venv/Lib/site-packages",
    ],
    // フォーマッターの設定。autopep8 を指定する。
    "python.formatting.provider": "autopep8",
    "python.jediEnabled": false,
    // Lintの設定
    "python.linting.mypyEnabled": true,
    "python.linting.pylintEnabled": false,
}

:slight_smile: パッケージをインストールします。
setting.json の設定を行うと、使用している依存パッケージをインストールするように促されます。

まず、ターミナルを表示して、仮想環境がアクティブになっているか確認します。
「表示」→「ターミナル」
以下のように「(qiita_test)」のように出ていればOK

(qiita_test) C:\~\qiita_test>

以下を実行して、パッケージをインストールします。

pipenv install autopep8 mypy --dev

また、サンプルソースように「Flask」「numpy」もインストールします。

pipenv install Flask numpy

「--dev」は、開発環境のみで使用するパッケージを指定するものです。つまり、AWSにデプロイするときは含まれないパッケージとなります。:thinking:

プログラムの作成(Flask)

簡単なサンプルプログラムを作成します。
リクエストに対して、json形式のレスポンスを返すWebAPIです。
作成したら実行してエラーが出ないか確認しましょう。:spider:

app.py
from flask import Flask, jsonify, request
import numpy as np

app = Flask(__name__)
app.config["JSON_AS_ASCII"] = False

@app.route("/")
def index():
    return jsonify({"language": "パイソン"})

# exp:http://127.0.0.1:5000/sqrt?val=4
@app.route("/sqrt")
def getSqrt():
    param = request.args.get('val')
    val = int(param)
    return jsonify({"sqrt": np.sqrt(val)})

# exp:http://127.0.0.1:5000/sqrt/4
@app.route("/sqrt/<value>")
def getSqrt2(value):
    val = int(value)
    return jsonify({"sqrt": np.sqrt(val)})

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

折り返し地点です。:rabbit::turtle:

IAMユーザーの作成(AWS)

ここからは、ローカルで作成したWebAPIを、AWSにデプロイしていきます。

AWSアカウントには、ルートユーザーとIAMユーザーの2つがあります。
:chicken:(親です):ルートユーザーは、すべての権限を持つアカウントです。IAMユーザーの管理も行います。
:hatched_chick:(子です):IAMユーザーは、プロジェクト単位や開発者単位で、個別に権限を持つアカウントです。

まず、ルートユーザーを作成し、AWSコンソールにログインした後に、IAMユーザーを作成します。
IAMユーザーは以下の2つを作成します。

:hatched_chick: zappaデプロイ用のアカウント
:hatched_chick: AWSコンソールで管理する用のアカウント

:slight_smile: zappaからデプロイする用のポリシーを作成します。
ポリシーとはIAMユーザーに付与する権限のことです。:cop:

AWSコンソールにルートユーザーでログインし、画面上の「サービス」→「IAM」を選択します。
「ポリシー」を選択して、[ポリシーの作成]を押します。
「JSON」タブを選択して、ポリシーを書き込みます。
参考:Pythonで作るはじめてのサーバレスアプリケーション Kindle版

zappa-simple-policy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "iam:AttachRolePolicy",
                "iam:CreateRole",
                "iam:GetRole",
                "iam:PutRolePolicy"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "iam:PassRole"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "apigateway:DELETE",
                "apigateway:GET",
                "apigateway:PATCH",
                "apigateway:POST",
                "apigateway:PUT",
                "events:DeleteRule",
                "events:DescribeRule",
                "events:ListRules",
                "events:ListTargetsByRule",
                "events:ListRuleNamesByTarget",
                "events:PutRule",
                "events:PutTargets",
                "events:RemoveTargets",
                "lambda:AddPermission",
                "lambda:CreateFunction",
                "lambda:DeleteFunction",
                "lambda:GetFunction",
                "lambda:GetFunctionConfiguration",
                "lambda:GetPolicy",
                "lambda:ListVersionsByFunction",
                "lambda:RemovePermission",
                "lambda:UpdateFunctionCode",
                "lambda:UpdateFunctionConfiguration",
                "cloudformation:CreateStack",
                "cloudformation:DeleteStack",
                "cloudformation:DescribeStackResource",
                "cloudformation:DescribeStacks",
                "cloudformation:ListStackResources",
                "cloudformation:UpdateStack",
                "cloudfront:updateDistribution",
                "logs:DescribeLogStreams",
                "logs:FilterLogEvents",
                "route53:ListHostedZones",
                "route53:ChangeResourceRecordSets",
                "route53:GetHostedZone",
                "s3:CreateBucket",
                "dynamodb:*"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:DeleteObject",
                "s3:GetObject",
                "s3:PutObject",
                "s3:CreateMultipartUpload",
                "s3:AbortMultipartUpload",
                "s3:ListMultipartUploadParts",
                "s3:ListBucketMultipartUploads"
            ],
            "Resource": [
                "*"
            ]
        }
    ]
}

[ポリシーの確認]を押して、「名前」を付けます。ここでは「zappa-simple-policy」としました。
[ポリシーの作成]を押して、zappa用のポリシーが出来ました。

:slight_smile: zappa用のIAMユーザーを作成します。
(AWSコンソールにルートユーザーでログインし、画面上の「サービス」→「IAM」を選択します。)

  1. 「ユーザー」を選択して、[ユーザーを追加]を押します。
  2. 「ユーザー名」を指定します。ここでは、「zappa-simple-user」としました。
  3. 「アクセスの種類」で「プログラムによるアクセス」に☑します。
  4. [次のステップ:アクセス権限]を押します。
  5. [既存のポリシーを直接アタッチ]を選択して、検索欄で「zappa-simple-policy」と入力し、☑します。
  6. [次のステップ:タグ]を押します。(飛ばします)
  7. [次のステップ:確認]を押します。
  8. [ユーザーの作成]を押します。
  9. 作成に成功すると、アクセスキーIDとシークレットアクセスキーが表示されるので、メモっておきます。:writing_hand:

:slight_smile: AWSコンソールで管理する用のIAMユーザーを作成します。

  1. 「ユーザー」を選択して、[ユーザーを追加]を押します。
  2. 「ユーザー名」を指定します。ここでは、「qiita-test」としました。
  3. 「アクセスの種類」で「AWS マネジメントコンソールへのアクセス」に☑します。
  4. [次のステップ:アクセス権限]を押します。
  5. [既存のポリシーを直接アタッチ]を選択して、以下を選択します。
    • AmazonAPIGatewayAdministrator
    • AWSLambdaFullAccess
    • AmazonDynamoDBFullAccess(今回は利用していないが、DynamoDBを利用する場合)
    • IAMUserChangePassword(3で初回ログイン時にパスワードを変更する設定にした場合、自動で選択されます)
  6. [次のステップ:タグ]を押します。(飛ばします)
  7. [次のステップ:確認]を押します。
  8. [ユーザーの作成]を押します。
  9. 作成に成功すると、アクセスキーIDとシークレットアクセスキーが表示されるので、メモっておきます。:writing_hand:

:angry:もう少し:bangbang:

ローカル環境をAWSにデプロイ(zappa)

zappaというpythonの拡張機能を使って、作成したプロジェクトをAWSにデプロイします。

:slight_smile: AWS CLIを設定します。
IAMユーザーの情報をプロファイル単位で管理するために、AWS CLIをインストールします。
参考:AWS CLIのインストール
pipからもインストールできるみたいです。参考:https://www.suzu6.net/posts/4/

コマンドプロンプトで以下を実行して、[default]のプロファイルを設定します。
とりあえずzappa用のIAMユーザー(zappa-simple-user)情報を設定しましょう。

aws configure

AWS Access Key ID [********************]:
AWS Secret Access Key [********************]:
Default region name [ap-northeast-1]:
Default output format [json]:

regionは東京です。

インストールフォルダ以下の credentials ファイルに、作成したzappa用のIAMユーザー(zappa-simple-user)情報を設定します。
メモ帳か何かで開いて編集しましょう。

~\.aws\credentials
[zappa-simple-user]
aws_access_key_id = ********************
aws_secret_access_key = ********************

:slight_smile: zappaをインストールします。
ターミナルにて、仮想環境がアクティブになっていることを確認してから、以下を実行します。

pipenv install zappa

次に初期設定を行います。

zappa init
  1. デプロイ環境の名前の指定。(デフォルトでも可)
  2. AWSプロファイルの指定。先ほどcredentialsファイルに設定した「zappa-simple-user」を指定します。
  3. S3バケットを利用するための仮の名前の指定。(デフォルトでも可)
  4. アプリケーションの起動ファイルの指定。.appファイルとして指定します。今回は「app.py」を起動したいので、「app.app」を指定します。
  5. リージョンごとの最適化設定。特にパフォーマンスが必要なければデフォルトにします。
  6. 作成される設定情報が表示されます。問題なければ、Enterで初期設定を終了します。

:slight_smile: デプロイします。
ターミナルにて、仮想環境がアクティブになっていることを確認してから、以下を実行します。

zappa deploy

成功すると以下のようにエンドポイントが表示されます。
リンクに飛ぶと、json形式の値が表示されます。

Deployment complete!: [リンク]

:slight_smile: AWSで確認してみます。
AWSコンソールで管理する用のIAMユーザーで、AWSコンソールにログインします。
「サービス」→「API Gateway」または「Lambda」を選択すると、デプロイしたアプリケーションを確認することができます。

ハイ、オツカレー(  ̄▽)_:tea:

おまけ

:slight_smile: zappaコマンド

デプロイ済みのアプリケーションを更新する.
zappa update dev
デプロイ済みのアプリケーションを削除する.
zappa undeploy dev
ログの確認.
zappa tail dev

:rolling_eyes: 課題
AWSのポリシーがいまいちわかっていない。(ので、本稿の設定はあくまで参考程度に)
githubを使ってバージョン管理も絡めてみる。

:thinking: なんで?

  • なんで、WebAPI作るの?

これから5G技術が普及することによって、オンライン環境は今より格段に拡がり、よりストレスレスな通信が可能になるから。
ユーザーの環境に依存しない開発ができ、色々なプラットフォームでリソースを共有できるから。

  • なんで、Pythonなの?

機械学習を勉強する上で、パッケージが豊富で、スクリプトもわかりやすく、参考事例も多いから。
参考書やサイトでコーディングしたリソースを形にしたくて、色々考えた結果 WebAPI という技術に至ったから。
(参考書のほとんどは、colaboratory等でデータ分析して「はいできましたね。~終わり~」となっていて、じゃあ具体的にどう活用するの?ってずっとモヤモヤしてました)

  • なんで、サーバーレスなの?

サーバーの構築技術にはあまり興味がなく、自分でサーバー立てるよりAmazonやMicrosoftのサービスを利用したほうが早そうだなって思ったから。
自前でサーバー運用するよりもコストパフォーマンスに優れているから。

参考サイト

Windows + Python + PipEnv + Visual Studio Code でPython開発環境
Zappaを使ってPythonのコードをAWS Lambdaにデプロイする

参考書籍です。こちらの筆者の環境はOSXでエディターは特に使ってません。
Pythonで作るはじめてのサーバレスアプリケーション Kindle版

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4