[PYTHON] [Note] Deploying Azure Functions for the first time

1.First of all

In this article, I'll use the HttpTrigger and TimerTrigger that I often use in Azure Functions. I will explain up to the point of deploying and running.

It's been quite long, so I'll give it a table of contents and a brief description.

section Term title Contents
2 - Preparation -
1 -Local environment Installation of software required to deploy Azure Functions
2 -Azure cloud environment Pre-create the services needed to deploy Azure Functions
3 - Creating a FunctionApp Create a FunctionApp from the console
4 - AzureFunctions type AvailableTriggerKind of
5 - Implementation of AzureFunctions Creating and modifying Python scripts
1 - requirements.Fix txt -
2 - HttpTrigger -
3 - TimerTrigger -
6 - Deploy Azure Functions -
1 -Deploy using Makefile -
7 - Debugging AzureFunctions Running and debugging from the console

2. Preparation

In order to deploy AzureFunctions, the following preparations are required on the local environment and the cloud environment side of Azure.

2.1 Local environment

In this article, we will build the environment on Mac.

To deploy AzureFunctions, you need to install the following two software.

Installation on Mac is easy with brew.

#Azure CLI installation
$ brew update && brew install azure-cli

#Install Azure Function Core Tools
$ brew tap azure/functions
$ brew install azure-functions-core-tools@3

#Login to Azure using Azure CLI
$ az login

The version used for deploying this time is as follows.

#Azure CLI version
$ az --version
azure-cli                         2.16.0
...

#Azure Functions Core Tools version
$ func --version
3.0.2912

2.2 Azure cloud environment

It is assumed that you already have an Azure account.

When deploying AzureFunctions It is useful to prepare the following resources in advance.

Service name Use Recommended prefix Mandatory
Resource Group Summarize the services required to deploy Azure Functions rg- O
StorageAccount Storage to hold files st- O
Log Analytics Keep logs log- O
Application Insights View log appi O

These resources basically ** do not need to be created once **. However, this time we will create AzureFunctions from the console. If you already have the above required services, you can skip to the next section.

Also, the prefixes for the names of these services have a format officially recommended by Azure. Therefore, it is recommended to take a look at this Official Document. (Some of the services deployed this time do not follow the example)

The services created this time are as follows.

--appi-gsy0911: Log related --gsy0911stdata: Storage used by the user to store data etc. --gsy0911stsys: Storage used by systems such as Azure Functions --log-gsy0911: Log related

スクリーンショット 2020-12-27 14.42.07.png

3. Create FunctionApp

Create Azure Functions from the console. Enter Function App in the search window and it will appear.

スクリーンショット 2020-12-27 18.31.07.png

Why the name is not Azure Functions I think this is because we will create multiple Azure Functions in this Function App. Click the Create button to create it.

スクリーンショット 2020-12-27 18.31.18.png

Fill in the required items in Basics.

item value
Functions App name gsy0911-function
Publish Code
Runtime stack Python
Version 3.8 (※1)
Region Japan East

In the Hosting item, select the gsy0911sys of the Storage Account you created earlier.

item value
Storage Account gsy0911sys
Operating System Linux
Plan type Consumption(※2)

スクリーンショット 2020-12-27 18.32.06.png

Fill in the Monitoring item as well.

item value
Application Insights appi-gsy0911

スクリーンショット 2020-12-27 18.32.24.png

Set any Tag you like for Tags. After creating up to this point, create.

スクリーンショット 2020-12-27 18.33.36.png

This completes the service to be created.

4. AzureFunctions type

AzureFunctions has various launch methods (triggers). In particular, I use the following four. As the name suggests, each one will be explained briefly.

Check the Official Documentation (https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-triggers-bindings?tabs=csharp) for other trigger examples. In addition to trigger, there is also the concept of binding, which I will not explain because I will not use it this time. For more information, please read the official documentation above.

This time, I will implement HttpTrigger and TimerTrigger among the above functions.

5. Implementation of AzureFunctions

If you want to create it from scratch, execute the following command and it will generate the necessary files. The runtime to run is Python, so enter 3.


$ func init test_function
Select a number for worker runtime:
1. dotnet
2. node
3. python
4. powershell
5. custom
Choose option: 3 {<- type `3`}
python
Found Python version 3.8.6 (python3).
Writing requirements.txt
Writing .gitignore
Writing host.json
Writing local.settings.json
Writing {current_directory}/test_function/.vscode/extensions.json

#After creation, a folder with the name of the function will be created, so move to that
$ cd test_function

#File created by func init command
$ tree
.
├── host.json
├── local.settings.json
└── requirements.txt

You have now generated the files needed to deploy to Azure Functions.

5.1 Modification of requirements.txt

Add a library called cerberus for validation.

requirements.txt


# Do not include azure-functions-worker as it may conflict with the Azure Functions platform

azure-functions
+ cerberus

5.2 Creating HttpTrigger

First, create HttpTrigger.

# test_function/Run below
$ func new
Select a number for template:
1. Azure Blob Storage trigger
2. Azure Cosmos DB trigger
3. Azure Event Grid trigger
4. Azure Event Hub trigger
5. HTTP trigger
6. Azure Queue Storage trigger
7. RabbitMQ trigger
8. Azure Service Bus Queue trigger
9. Azure Service Bus Topic trigger
10. Timer trigger
Choose option: 5 {<- type `5`}
HTTP trigger
Function name: [HttpTrigger] http_trigger {<- type `http_trigger`}
Writing {current_directory}/http_trigger/__init__.py
Writing {current_directory}/http_trigger/function.json
The function "http_trigger" was created successfully from the "HTTP trigger" template.

#File structure after creating HttpTrigger function
$ tree
.
├── host.json
├── local.settings.json
├── requirements.txt
└── http_trigger
    ├── __init__.py
    └── function.json

5.2.1 HttpTrigger functions.json

The name here must match the name of the argument to themain ()function in __init__.py.

function.json



{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}

This time I want to create an AzureFunctions that receives a POST method, so delete get. Also, I want to set the URL route when integrating with API Management, so add tech/qiita.

function.json


{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "authLevel": "function",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
+     "route": "tech/qiita",
      "methods": [
-        "get",
        "post"
      ]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "$return"
    }
  ]
}

5.2.2 HttpTrigger __init__.py

The following templates are created by default. However, there are the following disadvantages.

--You can use the logging module as it is, --The length of the return value of HttpResponse exceeds 120 characters (PEP8 violation) --ValueError exception handling is pass It is not a good sample program that can be used as a compliment.

Before modification__init__.py


import logging

import azure.functions as func


def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    name = req.params.get('name')
    if not name:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('name')

    if name:
        return func.HttpResponse(f"Hello, {name}. This HTTP triggered function executed successfully.")
    else:
        return func.HttpResponse(
             "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response.",
             status_code=200
        )

Therefore, rewrite everything. Here, the input parameters are validated using the library called cerberus that was added to requirements earlier.

After modification__init__.py



import json
from logging import getLogger, INFO

import azure.functions as func
from cerberus import Validator

logger = getLogger()
logger.setLevel(INFO)


# Validation
SCHEMA = {
    "name": {"type": "string"}
}


def main(req: func.HttpRequest) -> func.HttpResponse:
    """
A function that receives a payload like the one below
    {
        "name": "taro",
        "age": 10
    }
    """
    #Because it is intended for POST only
    payload = req.get_json()

    #Create a validator
    #Input of unknown parameters`allow_unknown`Allowed by
    validator = Validator(SCHEMA, allow_unknown=True)

    #If validation does not pass, throw an error
    if not validator.validate(payload, allow_unknown=True):
        return func.HttpResponse(
            body=json.dumps(validator.errors),
            mimetype="application/json",
            charset="utf-8",
            status_code=400
        )

    #If there is a correct input, the received payload is returned as it is
    return func.HttpResponse(
        body=json.dumps(payload),
        mimetype="application/json",
        charset="utf-8",
        status_code=200
    )

This completes the HttpTrigger code.

5.3 Creating a TimerTrigger

Next, create a TimerTrigger. Create a sample program from the command as before.

$ func new
Select a number for template:
1. Azure Blob Storage trigger
2. Azure Cosmos DB trigger
3. Azure Event Grid trigger
4. Azure Event Hub trigger
5. HTTP trigger
6. Azure Queue Storage trigger
7. RabbitMQ trigger
8. Azure Service Bus Queue trigger
9. Azure Service Bus Topic trigger
10. Timer trigger
Choose option: 10 {<- type `10`}
Timer trigger
Function name: [TimerTrigger] timer_trigger {<- type `timer_trigger`}
Writing {current_directory}/timer_trigger/readme.md
Writing {current_directory}/timer_trigger/__init__.py
Writing {current_directory}/timer_trigger/function.json
The function "timer_trigger" was created successfully from the "Timer trigger" template.

#Check the created file
$ tree
.
├── host.json
├── local.settings.json
├── requirements.txt
├── http_trigger
│   ├── __init__.py
│   └── function.json
└── timer_trigger
    ├── __init__.py
    ├── function.json
    └── readme.md

5.3.1 TimerTrigger functions.json

The execution timing can be modified with the schedule item. In this example, the setting is executed every 5 minutes.

functions.json


{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "name": "mytimer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 */5 * * * *"
    }
  ]
}

5.3.2 TimerTrigger __init__.py

TimerTrigger execution script. This is also rewritten.

Before modification__init__.py


import datetime
import logging

import azure.functions as func


def main(mytimer: func.TimerRequest) -> None:
    utc_timestamp = datetime.datetime.utcnow().replace(
        tzinfo=datetime.timezone.utc).isoformat()

    if mytimer.past_due:
        logging.info('The timer is past due!')

    logging.info('Python timer trigger function ran at %s', utc_timestamp)

Here is the modified execution script. No particular processing is described.

After modification__init__.py


from datetime import datetime, timezone, timedelta
from logging import getLogger, INFO

import azure.functions as func


logger = getLogger()
logger.setLevel(INFO)


def main(mytimer: func.TimerRequest):
    #Get date and time
    tz_jst = timezone(timedelta(hours=9))
    today = datetime.now(tz=tz_jst)

    logger.info(f"today: {today}")
    #Process the date from the following

This completes the TimerTrigger script.

6. Deploy Azure Functions

Deploy to Azure Functions in the environment logged in with $ az login It will be deployed automatically.

If you have multiple subscriptions, you must explicitly select them.

6.1 Deploy using Makefile

Use Makefile for deployment. You can use shell script etc., but Makefile is more convenient because it can be divided by command according to purpose by default. It is available for any Azure Functions deployment by changing FUNCTION_APP_NAME.

Makefile


# function app name to deploy
FUNCTION_APP_NAME := gsy0911-function


.PHONY: help
help: ## print this message ## make
	@echo "publish to $(FUNCTION_APP_NAME)"
	@printf "\033[36m%-30s\033[0m %-50s %s\n" "[Sub command]" "[Description]" "[Example]"
	@grep -E '^[/a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | perl -pe 's%^([/a-zA-Z_-]+):.*?(##)%$$1 $$2%' | awk -F " *?## *?" '{printf "\033[36m%-30s\033[0m %-50s %s\n", $$1, $$2, $$3}'

.PHONY: clean
clean: ## clean the function app ## make clean
	func azure functionapp publish $(FUNCTION_APP_NAME) --nozip

.PHONY: publish
publish: ## publish to the function app ## make publish
	func azure functionapp publish $(FUNCTION_APP_NAME)


If you execute the following $ make publish in the directory where the above Makefile is located, It can be deployed to Azure Functions specified by a constant.

#Show list of Make commands
$ make
publish to gsy0911-function
[Sub command]                  [Description]                                      [Example]
help                           print this message                                 make
clean                          clean the function app                             make clean
publish                        publish to the function app                        make publish

#Deploy to Azure Functions
$ make publish
...
Remote build succeeded!
Syncing triggers...
Functions in gsy0911-function:
    http_trigger - [httpTrigger]
        Invoke url: https://gsy0911-function.azurewebsites.net/api/tech/qiita?code=***

    timer_trigger - [timerTrigger]

Once the deployment is complete, you can see it from the console. The name of the deployed Functions matches the name of the locally created folder.

スクリーンショット 2020-12-27 19.04.33.png

7. AzureFunctions debugging

For simple testing, it's a good idea to run Azure Functions directly from the console.

Select the function you want to test run and select Test/Run from Code + Test.

スクリーンショット 2020-12-27 19.07.20.png

A screen will appear from the right, so enter the json format data there and execute Run.

スクリーンショット 2020-12-27 19.10.14.png

If successful, you can see that the set value is returned.

スクリーンショット 2020-12-27 19.21.54.png

In addition, the execution result log etc. is output to the place called Monitor. (However, the execution log is output with a lag of about 3 minutes after the execution of the function is completed.)

スクリーンショット 2020-12-27 19.30.29.png

You can run the test with TimerTrigger in the same way.

8. At the end

In this article, I briefly touched on the following:

--Deploying services required for Azure Functions --Create / deploy / debug Azure Functions --HttpTrigger and TimerTrigger --Deployment using Makefile

There is also an Article about Queue Trigger that I didn't mention this time, so please check it out as well.

Recommended Posts

[Note] Deploying Azure Functions for the first time
Kaggle for the first time (kaggle ①)
Kaguru for the first time
[For self-learning] Go2 for the first time
See python for the first time
Start Django for the first time
MongoDB for the first time in Python
Let's try Linux for the first time
I tried using scrapy for the first time
How to use MkDocs for the first time
I tried python programming for the first time.
I tried Mind Meld for the first time
A useful note when using Python for the first time in a while
Try posting to Qiita for the first time
What I got into Python for the first time
I tried Python on Mac for the first time.
Register a task in cron for the first time
I tried python on heroku for the first time
For the first time, I learned about Unix (Linux).
AI Gaming I tried it for the first time
Summary of stumbling blocks in Django for the first time
Introducing yourself at Qiita for the first time (test post)
I tried the Google Cloud Vision API for the first time
If you're learning Linux for the first time, do this!
Azure Functions: Try Durable Functions for Python
Differences C # engineers felt when learning python for the first time
I tried to create serverless batch processing for the first time with DynamoDB and Step Functions
I tried logistic regression analysis for the first time using Titanic data
Qiita's first post (the reason for starting)
Python Master RTA for the time being
A note about the functions of the Linux standard library that handles time
Impressions and memorandums when working with VS code for the first time
For the first time in Numpy, I will update it from time to time
Since I'm free, the front-end engineer tried Python (v3.7.5) for the first time.
Looking back on the machine learning competition that I worked on for the first time
Let's display a simple template that is ideal for Django for the first time
GTUG Girls + PyLadiesTokyo Meetup I went to machine learning for the first time
Upgrade the Azure Machine Learning SDK for Python
For the time being, import them into jupyter
Make a histogram for the time being (matplotlib)
Use logger with Python for the time being
Run yolov4 "for the time being" on windows
I played with Floydhub for the time being
Try using LINE Notify for the time being
virtualenv For the time being, this is all!
First time python
Import audit.log into Splunk and check the behavior when Splunk is started for the first time
[Note] The story of setting up the SDK for Python of Azure IoT Hub on Linux
After attending school, I participated in SIGNATE's BEGINNER limited competition for the first time.
First time python
I want to create a lunch database [EP1] Django study for the first time
I want to create a lunch database [EP1-4] Django study for the first time
Flow memo to move LOCUST for the time being
Run with CentOS7 + Apache2.4 + Python3.6 for the time being
[Python] Measures and displays the time required for processing
Molecular dynamics simulation to try for the time being
I will install Arch Linux for the time being.
Next to Excel, for the time being, jupyter notebook
Introduction to Deep Learning for the first time (Chainer) Japanese character recognition Chapter 1 [Environment construction]
What is a dog? Django--Getting Started with Form for the First Time POST Transmission Volume
What kind of environment should people who are learning Python for the first time build?