0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Python 3.0を使用してDevOpsのためのアリババクラウドFunction Computeを探る

Last updated at Posted at 2020-12-24

この記事では、Python 3.0を使用したサンプルプログラムを用いて、Alibaba Cloud Function Compute for DevOpsを探っていきます。

本ブログは英語版からの翻訳です。オリジナルはこちらからご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。

Alibaba Cloud Tech Share 執筆者、John Hanley。Tech Shareは、クラウドコミュニティ内で技術的な知識やベストプラクティスを共有することを奨励するAlibaba Cloudのインセンティブプログラムです。

Alibaba Cloud Function Computeは、イベント駆動型のサーバーレス・コンピューティング・プラットフォームであり、開発者はインフラストラクチャを管理する必要なくサービスを構築してデプロイすることができます。リソース管理、自動スケーリング、ロードバランシングをシームレスに処理するため、ビジネスロジックに集中して開発速度を向上させることができます。また、他のアリババサービスから様々なイベントソースを設定して、自動的にコードを実行するようにトリガーすることもできます。一番の利点は、コードが実際に消費するリソースを100ミリ秒単位で支払うだけでよいということです。

API Gatewayは、セキュアなAPIを簡単に大規模に公開できるマネージドサービスです。API Gatewayは、ECS、Function Compute、Webアプリケーションなど、多くのサービスとのインターフェースを提供しています。また、API GatewayはDNSサービスと統合して、ドメイン名ベースのAPIを提供します。

本日の記事では、Python 3を使用したサンプルプログラムを用いて、Alibaba Cloud Function Compute for DevOpsについて探っていきたいと思います。最終的な目標は、API Gateway、Function Compute、Direct Mailを組み合わせて、OSS上でホストされた静的なウェブサイトに適したコンタクトフォームを提供することです。

Function Computeインタフェース

Function Computeでコードを実行するには、いくつかの方法があります。SDKを介して、API Gatewayを介して、あるいはTriggersを介して、関数を "invoke "することができます。関数の定義は、どのサービスがあなたの関数を呼び出すかによって異なります。この記事では、2つの異なる呼び出しのスタイルを取り上げます。1つ目はHTTPトリガーによる方法、2つ目はAPI Gatewayによる方法です。なお、関数定義はPython用のものになります。Pythonの関数についてはこちらをご覧ください。

HTTPトリガーの関数定義では、HTTPトリガーとは何かを知る必要があります。HTTPトリガーとは、Function Compute コンソールで関数に割り当てるURLのことで、関数を呼び出すことができます。URLは次のようになります。

https://1234567891234567.ap-southeast-1.fc.aliyuncs.com/2016-08-15/proxy/service_name/function_name/

HTTPトリガーで呼び出された場合の関数定義

def my_handler(environ, start_response):
    context = environ['fc.context']
    request_uri = environ['fc.request_uri']
    for k, v in environ.items():
        if k.startswith("HTTP_"):
            # process custom request headers
            pass

    # do something here

    status = '200 OK'
    response_headers = [('Content-type', 'text/plain')]
    start_response(status, response_headers)
    return ["Hello World"]
アイテム 説明と使用方法
関数名 my_handlerは、作成された関数の "Handler "フィールドに対応していなければなりません。例えば、関数の作成時にHandlerがmain.my_handlerに設定されている場合、Function Computeは自動的にmain.pyで定義されたmy_handler関数をロードします。
environ environパラメータは、すべてのクライアント関連情報を保持するPython辞書です。詳細は environ パラメータのページを参照してください。
start_response start_response パラメータは callable です。詳細はstart_responseパラメータのページを参照してください。これはFCランタイムによって提供されます。必要な2つの位置パラメータとオプションのパラメータを受け付けます。
戻り値 関数が戻る際には、呼び出し元のサーバに結果を返す必要があります。HTTPレスポンスには、HTTPステータス、HTTPヘッダ、HTTPボディが含まれている必要があります。そのため、関数が戻り値としてHTMLボディを返す前に、start_response()を呼び出してHTTPステータスとHTTPヘッダの内容をサーバに返す必要があります。この関数はHTMLボディを返します。

Invoke APIまたはAPI Gatewayから呼び出された場合の関数定義

def my_handler(event, context):
    body = 'hello world'
    res = {
        'isBase64Encoded': False,
        'statusCode': 200,
        'headers': {
            'content-type' : 'text/plain'
        },
        'body': body
    }

    return json.dumps(res)
アイテム 説明と使用方法
関数名 my_handlerは、作成された関数の "Handler "フィールドに対応していなければなりません。例えば、関数作成時にHandlerがmain.my_handlerに設定されている場合、Function Computeは自動的にmain.pyで定義されたmy_handler関数をロードします。
イベントパラメータ イベントパラメータは、関数呼び出しに渡されるデータです。Function Computeは変換を行わず、ユーザ関数に値を渡すだけです。パラメータの型はPython2.7ではstr、Python3ではbytesです。
コンテキストパラメータ コンテキストパラメータには、関数の操作情報(リクエストIDや一時的なAccesskeyなど)が含まれています。パラメータはFCContext型です。Pythonガイドの項では、コンテキストの構造や使い方を説明しています。
戻り値 関数の戻り値は、関数を呼び出した結果として返されます。どのような型であっても構いません。単純な型の場合、Function Computeは結果を返す前に文字列に変換します。複雑な型の場合、Function Computeは結果を返す前にJSON文字列に変換します。

HTMLでパラメータ "environ "を返すプログラム例

この例は、HTTPトリガー(HTTP URL)によって呼び出される関数の例です。

Function Compute にアップロードするためのサンプルプログラムをダウンロードしてください。

このプログラムが生成する出力を表示します。データの一部はセキュリティ上の理由でマスクされていることに注意してください。

############################################################
# Version 1.01
# Date Created: 2018-05-25
# Last Update:  2018-05-29
# https://www.neoprime.io
# Copyright (c) 2018, NeoPrime, LLC
############################################################

""" Alibaba Cloud Function Compute Example """
""" This program will return the environment back to the caller as an HTML table """
""" This is useful to learn about the running environment in Function Compute """
""" This code is designed to be called thru HTTP URL via an HTTP Trigger """

def handler(environ, start_response):
    body = '<!DOCTYPE html>\n<html lang="en"><head>\n'
    body = body + '<style>\n'
    body = body + 'table, th, td {border: 1px solid black;}\n'
    body = body + 'table {border-collapse: collapse;}\n'
    body = body + 'th, td {border: 1px solid #ddd; padding 8px;}\n'
    body = body + 'th {padding-top: 12px; padding-bottom: 12px;\n'
    body = body + 'text-align: left; background-color: #4CAF50;color: white;}\n'
    body = body + 'tr:nth-child(even){background-color: #f2f2f2;}\n'
    body = body + 'tr:hover {background-color: #ddd;}\n'
    body = body + '</style>\n'
    body = body + '</head>\n<body><table width="%100%">\n'
    body = body + "<thead>\n<tr><th>Name</th><th>Type</th><th>Value</th></tr>\n</thead>\n"
    body = body + "<tbody>\n"

    for k, v in environ.items():
      body = body + "<tr>"
      body = body + "<td>" + k + "</td>"
      body = body + "<td>" + type(v).__name__ + "</td>"
      if isinstance(v, bool):
        body = body + "<td>" + str(v) + "</td>"
      if isinstance(v, str):
        body = body + "<td>" + v + "</td>"
      if isinstance(v, tuple):
        body = body + "<td>" + str(v) + "</td>"
      if isinstance(v, type):
        body = body + "<td>" + str(v) + "</td>"
      body = body + "</tr>\n"

    body = body + "</tbody>\n</table>\n</body></html>"
    status = '200 OK'
    response_headers = [('Content-type', 'text/html')]
    start_response(status, response_headers)
    return [bytes(body, "utf-8")]

HTMLでパラメータ "context "を返すプログラム例

この例は、API Gatewayから呼び出される関数のためのものです。

サンプルプログラムをダウンロードして、Function Computeにアップロードします。

このプログラムが生成する出力を表示します。データの一部はセキュリティ上の理由でマスクされていることに注意してください。

############################################################
# Version 1.01
# Date Created: 2018-05-25
# Last Update:  2018-05-29
# https://www.neoprime.io
# Copyright (c) 2018, NeoPrime, LLC
############################################################

""" Alibaba Cloud Function Compute Example """
""" This program will return the environment back to the caller as an HTML table """
""" This is useful to learn about the running environment in Function Compute """
""" This code is designed to be called thru API Gateway using an HTTP URL """

import json

# Add a row to the HTML table
def add_row(body, name, value):
    """ body - the current HTML body string that we append to """
    """ name - the name of the item. Added to the first column """
    """ value - the value to add. The type is added to the second column, value to the third """
    """ returns body """

    # begin a new table row
    body = body + '<tr>\n'
    body = body + '<td>' + name + '</td>\n'
    body = body + '<td>' + type(value).__name__ + '</td>\n'

    if isinstance(value, str):
        # Keep the string length less than 85 characters
        v = (value[:85] + ' ...') if len(value) > 85 else value
        body = body + '<td>' + v + '</td>\n'
    else:
        body = body + '<td>' + str(value) + '</td>\n'

    return body + '</tr>\n'

# Add a "dict" item to the table by parsing thru each item in the dictionary
def add_dict(body, name, item):
    """ body - the current HTML body string that we append to """
    """ name - the name of the item. """
    """ item - The item to process """
    for k in item:
        if isinstance(item[k], dict):
            body = add_dict(body, name + "." + k, item[k])
        else:
            body = add_row(body, name + "." + k, item[k])
    return body

def add_event(body, event):
    j = json.loads(event.decode("utf-8"))
    return add_dict(body, "event", j)

def add_context(body, context):
    body = add_row(body, 'context.request_id', context.request_id)
    body = add_row(body, 'context.region', context.region)
    body = add_row(body, 'context.account_id', context.account_id)
    body = add_row(body, 'context.function.handler', context.function.handler)
    body = add_row(body, 'context.function.memory', context.function.memory)
    body = add_row(body, 'context.function.name', context.function.name)
    body = add_row(body, 'context.function.timeout', context.function.timeout)
    body = add_row(body, 'context.credentials.accessKeyId', context.credentials.accessKeyId)
    body = add_row(body, 'context.credentials.accessKeySecret', context.credentials.accessKeySecret)
    body = add_row(body, 'context.credentials.access_key_id', context.credentials.access_key_id)
    body = add_row(body, 'context.credentials.access_key_secret', context.credentials.access_key_secret)
    body = add_row(body, 'context.credentials.securityToken', context.credentials.securityToken)
    body = add_row(body, 'context.credentials.security_token', context.credentials.security_token)
    body = add_row(body, 'context.service.log_project', context.service.log_project)
    body = add_row(body, 'context.service.log_store', context.service.log_store)

    return body

def build_html(body, event, context):
    body = '<!DOCTYPE html>\n<html lang="en"><head>\n'
    body = body + '<style>\n'
    body = body + 'table, th, td {border: 1px solid black;}\n'
    body = body + 'table {border-collapse: collapse;}\n'
    body = body + 'th, td {border: 1px solid #ddd; padding 8px;}\n'
    body = body + 'th {padding-top: 12px; padding-bottom: 12px;\n'
    body = body + 'text-align: left; background-color: #4CAF50;color: white;}\n'
    body = body + 'tr:nth-child(even){background-color: #f2f2f2;}\n'
    body = body + 'tr:hover {background-color: #ddd;}\n'
    body = body + '</style>\n'
    body = body + '</head>\n<body><table width="100%">\n'
    body = body + '<thead>\n<tr><th>Name</th><th width="5%">Type</th><th>Value</th></tr>\n</thead>\n'
    body = body + '<tbody>\n'

    body = add_event(body, event)
    body = add_context(body, context)

    body = body + '</tbody>\n'
    body = body + '</table>\n</body></html>'

    return body

def handler(event, context):
    body = ""
    body = build_html(body, event, context)

    res = {
        'isBase64Encoded': False,
        'statusCode': 200,
        'headers': {
            'content-type' : 'text/html'
        },
        'body': body
    }

    return json.dumps(res)

サンプルプログラムでは、関数の環境や関数呼び出しで渡したパラメータを表示することができるようになります(HTTP経由かAPI Gatewayのどちらか)。

次回の記事では、署名付きのREST APIを使ってDirectMailのコードを作成します。次の記事では、HTMLコンタクトフォーム、API Gateway、Function Compute、DirectMailをサーバーレスシステムに統合して、ウェブサイトのコンタクトページを提供します。Webサイトは、OSS上の動的Webサイトでも静的Webサイトでもどちらでも構いません。

Function Computeのアクセスキー

ここでは、Function Computeのアクセスキーを安全に管理する方法について説明します。RAMロールです。ロールを使用すると、Alibaba Consoleでロールを介してアクセスキーを作成し、そのロールをFunction Computeサービスに割り当てることができます。これにより、ソースコードでキーが必要になることを防ぐことができます。ロールの資格情報は、context.credentialsパラメータを介して関数で利用できるようになります。

Resource Access Managementコンソールで、必要なパーミッションを持つロールを作成します。そして、このロールをFunction Computeサービスに割り当てます。このサービスの下に位置する各関数には、このロールが割り当てられています。

アリババドキュメンテーション

Function Compute:
アリババ Function Computeの製品ページ
アリババ Function Compute ドキュメント
アリババ Function Compute トリガー

API Gateway:
アリババAPIゲートウェイ製品ページ
アリババAPIゲートウェイのドキュメント
API Gateway SSL証明書のインストール

アリババクラウドは日本に2つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
アリババクラウドジャパン公式ページ

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?