flask部署到云端

    科技2022-08-01  144

    flask部署到云端

    Lately I’ve had the opportunity to learn how to host a Flask application on Google Cloud Platform (GCP) using Cloud Run and Cloud Endpoints. Though official documentation is provided, it took me some time to understand and implement the various components correctly. In this article, I am going to show you how to deploy a Flask app on Cloud Run with authentication. I hope the article can help someone, who is interested in deploying a web application on GCP with authentication process.

    最近,我有机会学习如何使用Cloud Run和Cloud Endpoints在Google Cloud Platform(GCP)上托管Flask应用程序。 尽管提供了官方文档,但我还是花了一些时间来正确理解和实现各种组件。 在本文中,我将向您展示如何在具有身份验证的Cloud Run上部署Flask应用 。 希望本文能对有兴趣在GCP上通过身份验证过程部署Web应用程序的人有所帮助。

    今天的申请 (Today’s application)

    We are interested in deploying a web application:

    我们对部署Web应用程序感兴趣:

    With Flask;

    用烧瓶; Running on Cloud Run;

    在Cloud Run上运行; Using production ready server (e.g. gunicorn);

    使用生产就绪的服务器(例如gunicorn); Protected by Cloud Endpoints (requests are checked by the endpoint, i.e. not everyone can access to the application).

    受Cloud Endpoints保护(请求由端点检查,即,不是每个人都可以访问该应用程序)。

    步骤1:建立Flask应用程式 (Step 1: Create a Flask application)

    A simple Flask application on Cloud Run Cloud Run上的简单Flask应用程序

    We are interested in a Flask application, with some simple methods. The code below defines three endpoints:

    我们对使用一些简单方法的Flask应用程序感兴趣。 下面的代码定义了三个端点:

    GET /hello

    GET /hello

    GET /hello/<my_name>

    GET /hello/<my_name>

    POST /hello_body

    POST /hello_body

    """ A sample flask application on Cloud Run. Version 1 """ from flask import Flask from flask_cors import CORS from flask_sslify import SSLify from webargs import fields from webargs.flaskparser import use_args # Initialise flask app app = Flask(__name__) CORS(app, supports_credentials=True) sslify = SSLify(app) @app.route("/hello", methods=["GET"]) def hello(): """Method 1: Return a simple hello""" return "Hello", 200 @app.route("/hello/<my_name>", methods=["GET"]) def hello_name(my_name): """Method 2: Return hello with name, given in url""" return f"Hello from url, {my_name}", 200 @app.route("/hello_body", methods=["POST"]) @use_args(argmap={"my_name": fields.Str(required=True)}) def hello_from_body(args): """Method 3: Return hello with name, given in body""" my_name = args.get("my_name", "") return f"Hello from body, {my_name}", 200 @app.route("/") def top_page(): """top_page""" return "Welcome to my application, version 1\n" if __name__ == "__main__": app.run(ssl_context="adhoc", host="0.0.0.0", port=5000)

    步骤2:在Cloud Run上部署Flask应用程序 (Step 2: Deploy the Flask application on Cloud Run)

    We are now interested in building a Docker image for the Flask application, since applications on Cloud Run are deployed from Docker images. For this step, the official documentation by GCP can be found from here. From now, we are going to use some linux commands on my terminal.

    我们现在对为Flask应用程序构建Docker映像感兴趣,因为Cloud Run上的应用程序是从Docker映像部署的。 对于此步骤,可以从此处找到GCP的官方文档。 从现在开始,我们将在终端上使用一些linux命令。

    2.1设置GCP帐户,项目等 (2.1 Set up GCP account, project, etc.)

    First of all, we install Cloud SDK, which enables to connect to the GCP via a terminal on your local machine. After the install, we shall make sure the relevant account and project name are set as default.

    首先,我们安装Cloud SDK,该软件可以通过本地计算机上的终端连接到GCP。 安装后,我们应确保将相关帐户和项目名称设置为默认名称。

    # Setup GCP account$ gcloud config set account $MY_EMAIL_ADDRESS$ gcloud auth login $MY_EMAIL_ADDRESS$ gcloud config set project $MY_PROJECT_ID

    2.2构建Flask应用程序的Docker映像 (2.2 Build a Docker image of the Flask application)

    Now, we are going to build a Docker image of the Flask application. In this example, we need Dockerfile andrequirements.txt files, which are saved in the same folder to main_v1.py:

    现在,我们将构建Flask应用程序的Docker映像。 在此示例中,我们需要Dockerfile和requirements.txt文件,它们保存在同一文件夹中的main_v1.py :

    flaskapp_cr├── main_v1.py├── requirements.txt└── Dockerfile

    We are going to use an instantiated Flask application, which is defined in main_v1.py. Therefore, the entrypoint for gunicorn should be defined as main_v1:app . The Dockerfile now reads:

    我们将使用实例化的Flask应用程序,该应用程序在main_v1.py定义。 因此, gunicorn的入口gunicorn应定义为main_v1:app 。 Dockerfile现在读取:

    # Use Python37FROM python:3.7# Copy requirements.txt to the docker image and install packagesCOPY requirements.txt /RUN pip install -r requirements.txt# Set the WORKDIR to be the folderCOPY . /app# Expose port 5000EXPOSE 5000ENV PORT 5000WORKDIR /app# Use gunicorn as the entrypointCMD exec gunicorn --bind :$PORT main_v1:app --workers 1 --threads 1 --timeout 60

    We shall build the Docker image and push it to Container Registry on GCP. The service name is defined as flaskapp_cr.

    我们将构建Docker映像并将其推送到GCP上的Container Registry。 服务名称定义为flaskapp_cr 。

    # Build Docker on your local machine$ docker build -t gcr.io/$MY_PROJECT_ID/flaskapp_cr:v1 -f Dockerfile .# Push the Docker image to Container Registry $ docker push gcr.io/$MY_PROJECT_ID/flaskapp_cr:v1

    If successful, we are able to see the docker image on Container Registry.

    如果成功,我们可以在Container Registry上看到docker镜像。

    The docker image is now saved in Container Registry Docker映像现在保存在Container Registry中

    2.3从Container Registry中选择Docker映像并在Cloud Run上进行部署 (2.3 Select the Docker image from Container Registry and deploy on Cloud Run)

    From Container Registry, we are able to deploy flaskapp_cr Docker image on Cloud Run via gcloud command. We shall name the instance as flaskapp-cr-v1.

    通过Container Registry,我们能够通过gcloud命令在Cloud Run上部署flaskapp_cr Docker映像。 我们将实例命名为flaskapp-cr-v1 。

    # Deploy a Docker image on Cloud Run$ gcloud run deploy flaskapp-cr-v1 \ --image gcr.io/$MY_PROJECT_ID/flaskapp_cr:v1 \ --region us-east1 \ --platform managed \ --memory 128Mi

    Once the instance flaskapp-cr-v1 is created, we are able to see the logs on the terminal:

    创建实例flaskapp-cr-v1 ,我们可以在终端上查看日志:

    Service [flaskapp-cr-v1] revision [flaskapp-cr-v1-00001-hey] has been deployed and is serving 100 percent of traffic at https://flaskapp-cr-v1-yerjarnciq-ue.a.run.app

    We are now able to check the Cloud Run instance from the console.

    现在,我们可以从控制台检查Cloud Run实例。

    This instance flaskapp-cr-v1 can be accessed by anyone since we allowed “unauthenticated access” when we deployed it. We will add authentication later.

    任何人都可以访问 flaskapp-cr-v1实例,因为我们在部署它时允许“未经flaskapp-cr-v1验证的访问”。 稍后我们将添加身份验证。

    Note: Allow unauthenticated. Everyone can access to this instance 注意:允许未经身份验证。 每个人都可以访问该实例

    2.4在Cloud Run上检查Flask应用程序 (2.4 Check the Flask application on Cloud Run)

    Let’s create some HTTPS requests to the Cloud Run instance. Since we have three Flask methods, we shall send three requests to flaskapp-cr-v1.

    让我们为Cloud Run实例创建一些HTTPS请求。 由于我们有三种Flask方法,因此我们将向flaskapp-cr-v1发送三个请求。

    import requestsurl = "https://flaskapp-cr-v1-yerjarnciq-ue.a.run.app"# Method 1resp = requests.get(f"{url}/hello", verify=False)print(resp.content.decode())# Method 2resp = requests.get(f"{url}/hello/Foo bar", verify=False)print(resp.content.decode())# Method 3 resp = requests.post(f"{url}/hello_body", data={"my_name": "Foo bar"}, verify=False)print(resp.content.decode())

    The response can be found from the log on flaskapp-cr-v1 instance on Cloud Run.

    可以从Cloud Run上flaskapp-cr-v1实例的日志中找到响应。

    Excellent! We have deployed a Flask application on Cloud Run.

    优秀的! 我们已经在Cloud Run上部署了Flask应用程序。

    步骤3:在Cloud Run上添加身份验证端点 (Step 3: Add authentication endpoint on Cloud Run)

    So far, we are able to deploy a Flask application on Cloud Run. However, the problem is that everyone can send requests to the Cloud Run instance. If we leave the Cloud Run instance running on https://flaskapp-cr-v1-yerjarnciq-ue.a.run.app, everyone on the planet can access it.

    到目前为止,我们已经能够在Cloud Run上部署Flask应用程序。 但是,问题在于每个人都可以将请求发送到Cloud Run实例 。 如果我们让Cloud Run实例在https://flaskapp-cr-v1-yerjarnciq-ue.a.run.app上运行,则地球上的每个人都可以访问它。

    We shall add authentication to the Flask application on Cloud Run. There are numerous ways to do this, but we shall add a Cloud Endpoint, which protects the Cloud Run instance. The official documentation by GCP can be found here.

    我们将在Cloud Run上向Flask应用程序添加身份验证。 有很多方法可以做到这一点,但是我们将添加一个Cloud Endpoint ,它可以保护Cloud Run实例。 GCP的官方文档可在此处找到。

    The ideas we are going to implement are below:

    我们将要实现的想法如下:

    Cloud Endpoint protects Flask application Cloud Endpoint保护Flask应用程序 A user creates an HTTPS request to Cloud Endpoints, instead of a to Cloud Run directly;

    用户向Cloud Endpoints创建HTTPS请求,而不是直接向Cloud Run创建HTTPS请求。 We are not allowed to make requests to the Flask application on Cloud Run directly;

    我们不允许直接向Cloud Run上的Flask应用程序发出请求; From the user side, requests must contain an authentication header. The header has a JSON Web Token (JWT). The JWT is created based on a Service account on GCP;

    从用户端,请求必须包含身份验证标头。 标头具有JSON Web令牌(JWT)。 JWT是根据GCP上的服务帐户创建的; Deploy a Cloud Endpoint on Cloud Run, which checks whether the HTTPS request from a user is valid (i.e. check the provided JWT is valid);

    在Cloud Run上部署Cloud Endpoint,以检查来自用户的HTTPS请求是否有效(即,检查所提供的JWT是否有效);

    The Cloud Endpoint configuration is set by a .yaml file.

    Cloud Endpoint配置由.yaml文件设置。

    3.1设置服务帐户并在本地计算机上创建JWT (3.1 Set up a service account and create JWT on local machine)

    We are interested in introducing an authentication process to the Flask application on Cloud Run. For GCP applications, we are able to create some authentication token, which shows that the person who has the token is the right person to access to the instance. In this example, we shall consider using a JSON Web Token (JWT). In this post, we skip the details of JWT.

    我们有兴趣向Cloud Run上的Flask应用程序引入身份验证过程。 对于GCP应用程序,我们能够创建一些身份验证令牌,这表明拥有令牌的人是访问实例的合适人选。 在此示例中,我们将考虑使用JSON Web令牌(JWT)。 在本文中,我们跳过了JWT的详细信息。

    There are multiple ways to create a JWT (e.g. using Firebase account), but we are going to have a look at a method based on using a Service account. The official document by GCP can be found from here.

    创建JWT的方法有多种(例如,使用Firebase帐户),但是我们将基于使用服务帐户的方法进行研究。 GCP的官方文件可以在这里找到。

    On the GCP console, we can go to IAM & Admin > Service Accounts. And then, we are able to create a Service account, and create a credential key of the corresponding Service account as a .json file.

    在GCP控制台上,我们可以转到IAM & Admin > Service Accounts 。 然后,我们可以创建一个服务帐户,并将相应服务帐户的凭据密钥创建为.json文件。

    Here is a sample code to create a JWT based on a Service account.

    这是一个示例代码,用于基于Service帐户创建JWT。

    """ A sample code to create a JWT key """ import time import google.auth.crypt import google.auth.jwt def generate_jwt(sa_keyfile, sa_email, expire, aud): """Create a jwt from service account""" current_time_int = int(time.time()) # Build the JWT payload payload = { "iat": current_time_int, "exp": current_time_int + expire, # When the token will expire "iss": sa_email, "aud": aud, # aud: need to match to yaml file parameter "sub": sa_email, "email": sa_email, } # Use the payload and keyfile to create JWT signer = google.auth.crypt.RSASigner.from_service_account_file(sa_keyfile) # create token jwt = google.auth.jwt.encode(signer, payload) return jwt.decode()

    For this script, we can give relevant values to create a JWT with Service account credential file. Note, both MY_SERVICE_ACCOUNT_ADDRESS and AUD_URL are used later to configure the Cloud Endpoint with .yaml file.

    对于此脚本,我们可以提供相关值以创建带有Service帐户凭据文件的JWT。 注意, AUD_URL将使用MY_SERVICE_ACCOUNT_ADDRESS和AUD_URL来通过.yaml文件配置Cloud Endpoint。

    from create_jwt_from_sa import generate_jwtsa_keyfile = $MY_CREDENTIAL_JSON_FILEsa_email = $MY_SERVICE_ACCOUNT_ADDRESSexpire = 300 # you can set some integeraud = $AUD_URLjwt = generate_jwt(sa_keyfile, sa_email, expire, aud)

    We are able to see which information is saved in thejwt on some website, e.g. https://jwt.io/. The jwt will be sent as a part of request header to the Flask application on Cloud Run.

    我们可以看到在某些网站的jwt保存了哪些信息,例如https://jwt.io/ 。 jwt将作为请求标头的一部分发送到Cloud Run上的Flask应用程序。

    3.2更新云运行 (3.2 Update the Cloud Run)

    We shall setup Cloud Run instance again, but we are not allowed to make any HTTPS requests to the Cloud Run instance directly this time. Let’s create a new instance called flaskapp-cr-v2. The same Docker image on Container Registry is used.

    我们将再次设置Cloud Run实例,但是这次我们不允许直接向Cloud Run实例发出任何HTTPS请求 。 让我们创建一个名为flaskapp-cr-v2的新实例。 使用Container Registry上的相同Docker映像。

    # Deploy a Docker image on Cloud Run. Not allowed unauthenticated access$ gcloud run deploy flaskapp-cr-v2 \ --image gcr.io/$MY_PROJECT_ID/flaskapp_cr:v1 \ --region us-east1 \ --platform managed \ --memory 128Mi \--no-allow-unauthenticated

    On the console, we can see a new instance on Cloud Run; nevertheless, the new instance flaskapp-cr-v2 does not allow unauthenticated access.

    在控制台上,我们可以在Cloud Run上看到一个新实例。 但是,新实例flaskapp-cr-v2不允许未经flaskapp-cr-v2验证的访问。

    Therefore, if we send HTTPS requests to the instance, the status is now 403 Forbidden.

    因此,如果我们将HTTPS请求发送到实例,则状态现在为403 Forbidden 。

    3.3在云运行上创建云端点 (3.3 Create a Cloud Endpoint on Cloud Run)

    Now, it is time to create a Cloud Endpoint. The official documentation by GCP can be found here. First of all, we deploy the Extensible Service Proxy V2 Beta (ESPv2 Beta) as an API gateway (which is provided on Container Registry as default). The Cloud Endpoint is deployed on Cloud Run as an instance called flaskapp-cr-v2-gateway.

    现在,该创建一个Cloud Endpoint了。 GCP的官方文档可在此处找到。 首先,我们将可扩展服务代理V2 Beta(ESPv2 Beta)部署为API网关(默认情况下在Container Registry上提供)。 Cloud Endpoint作为名为flaskapp-cr-v2-gateway的实例部署在Cloud Run上。

    $ gcloud run deploy flaskapp-cr-v2-gateway \ --image "gcr.io/endpoints-release/endpoints-runtime-serverless:2.17.0" \ --allow-unauthenticated \ --platform managed \ --project $MY_PROJECT_ID \ --region us-east1

    Once the gateway instance (i.e. Cloud Endpoint) is created on Cloud Run, we need to find two parameters from the instances.

    在Cloud Run上创建网关实例(即Cloud Endpoint)后,我们需要从实例中找到两个参数。

    URL of flaskapp-cr-v2

    flaskapp-cr-v2网址

    URL of flaskapp-cr-v2-gateway — https://

    flaskapp-cr-v2-gateway — https:// URL flaskapp-cr-v2-gateway — https://

    # URL for Flask application on Cloud RunAPPLICATION_URL = "https://flaskapp-cr-v2-yerjarnciq-ue.a.run.app"# URL for Cloud Endpoint on Cloud Run - "https://"ENDPOINT_HOST = "flaskapp-cr-v2-gateway-yerjarnciq-ue.a.run.app"## Also need to have parameters below$MY_SERVICE_ACCOUNT_ADDRESS$AUD_URL

    Once these two parameters are found, we can make a .yaml file, which configures the connection between a) the instance of the Flask application on Cloud Run and b) the cloud endpoint on Cloud Run. In this .yaml file, we also configure the service account, Flask method, etc.

    找到这两个参数后,我们可以制作一个.yaml文件,该文件配置a)Cloud Run上的Flask应用程序实例与b)Cloud Run上的云端点之间的连接。 在此.yaml文件中,我们还配置了服务帐户,Flask方法等。

    swagger: '2.0' info: title: Protected API with a Service account description: Protected API with a Service account version: v2 host: "$ENDPOINT_HOST" x-google-endpoints: - name: "$ENDPOINT_HOST" allowCors: True schemes: - https produces: - application/json x-google-backend: address: "$APPLICATION_URL" protocol: h2 securityDefinitions: api_key: type: "apiKey" name: "key" in: "query" google_service_account: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "$MY_SERVICE_ACCOUNT_ADDRESS" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/$MY_SERVICE_ACCOUNT_ADDRESS" x-google-audiences: "$AUD_URL" paths: /hello: # Method 1 get: summary: Return a simple hello operationId: hello produces: - "application/json" responses: 200: description: "" security: - google_service_account: [] /hello/{my_name}: # Method 2 get: description: Return hello with name, given in url operationId: hello_name parameters: - name: my_name in: path required: true type: string description: '' responses: 200: description: "" security: - google_service_account: [] /hello_body: # Method 3 post: description: Return hello with name, given in body operationId: hello_from_body responses: 200: description: "" security: - google_service_account: []

    Once the .yaml file is created, deploy the file using gcloud command.

    创建.yaml文件后,请使用gcloud命令部署该文件。

    $ gcloud endpoints services deploy cloud_endpoint_config.yaml \ --project=$MY_PROJECT_ID

    If the configuration is deployed, we will get CONFIG_ID, from logs on the terminal.

    如果部署了配置,我们将从终端上的日志中获取CONFIG_ID 。

    Service Configuration [2020-09-09r0] uploaded for service [flaskapp-cr-v2-gateway-yerjarnciq-ue.a.run.app]

    After the configuration is updated, we shall build a new ESPv2 image, using gcloud_build_image script. The code can be downloaded from here.

    更新配置后,我们将使用gcloud_build_image脚本构建一个新的ESPv2映像。 可以从这里下载代码。

    # Configuration ID is now givenCONFIG_ID = 2020-09-09r0$ chmod +x gcloud_build_image$ ./gcloud_build_image -s $ENDPOINT_HOST -c $CONFIG_ID -p $MY_PROJECT_ID

    After a new ESPv2 Docker image is created, we re-deploy the image on Cloud Run as Cloud Endpoint.

    创建新的ESPv2 Docker映像后,我们在Cloud Run作为Cloud Endpoint上重新部署该映像。

    # Re-deploy the gateway with the new docker image# gcloud run deploy flaskapp-cr-v2-gateway \ --image gcr.io/$MY_PROJECT_ID/endpoints-runtime-serverless:2.17.0-$ENDPOINT_HOST-$CONFIG_ID \ --allow-unauthenticated \ --platform managed \ --project $MY_PROJECT_ID \ --region us-east1

    That is all for configuring Cloud Endpoint. Now, we can check the flaskapp-cr-v2-gateway instance on Cloud Run, which protects flaskapp-cr-v2 instance.

    以上就是配置Cloud Endpoint的全部内容。 现在,我们可以在Cloud Run上检查flaskapp-cr-v2-gateway实例,以保护flaskapp-cr-v2实例。

    步骤4:检查Cloud Endpoint和Flask应用程序 (Step 4: Check the Cloud Endpoint and the Flask application)

    Cloud Endpoint protects Flask application Cloud Endpoint保护Flask应用程序

    It is time to check the application. We are not able to access to the Flask application on Cloud Run directly. If we go to the flaskapp-cr-v2-gateway url, we can see an error message, related to jwt.

    现在该检查应用程序了。 我们无法直接在Cloud Run上访问Flask应用程序。 如果我们转到flaskapp-cr-v2-gateway网址,我们会看到与jwt相关的错误消息。

    We shall make HTTPS requests to the Cloud Endpoint. The sample code is below. For each method (three methods in total), we send two requests as

    我们将向Cloud Endpoint发出HTTPS请求。 示例代码如下。 对于每种方法(总共三种方法),我们发送两个请求

    Without header

    没有标题

    With header {"Authorization": f"Bearer {jwt}"}

    使用标头{"Authorization": f"Bearer {jwt}"}

    The jwt is created by a service account; the same service account is hardcoded in the .yaml file for Cloud Endpoint configuration.

    jwt由服务帐户创建; .yaml文件中将相同的服务帐户硬编码为Cloud Endpoint配置。

    """ Send a request to flask application """ import requests from create_jwt_from_sa import generate_jwt # Paramters for JWT sa_keyfile = # MY_CREDENTIAL_JSON_FILE sa_email = # MY_SERVICE_ACCOUNT_ADDRESS expire = 300 aud = # AUD_URL # Create JWT jwt = generate_jwt(sa_keyfile, sa_email, expire, aud) # Header for Autheorizarion (Checked by Cloud Endpoint) auth_header = {"Authorization": f"Bearer {jwt}"} # Endpoint URL url = # ENDPOINT_URL # Name my_name = "Foo bar" # Request 1) without header and 2) with header for header in [{}, auth_header]: # Method 1 resp = requests.get(f"{url}/hello", verify=False, headers=header) print(resp.content.decode()) # Method 2 resp = requests.get(f"{url}/hello/{my_name}", verify=False, headers=header) print(resp.content.decode()) # Method 3 resp = requests.post( f"{url}/hello_body", data={"my_name": my_name}, headers=header, verify=False ) print(resp.content.decode())

    As we expect, the first three requests are blocked by the Cloud Endpoint as

    正如我们期望的那样,前三个请求被Cloud Endpoint阻止,因为

    {"code":401,"message":"Jwt is missing"}

    The last three requests are successfully made to Flask application.

    最后三个请求已成功向Flask应用程序发出。

    HelloHello from url, Foo barHello from body, Foo bar

    The logs on Cloud Endpoint is below. The first three requests have Error 401, whereas the last three requests are Status 200.

    Cloud Endpoint上的日志如下。 前三个请求的Error 401 ,而后三个请求的Status 200 。

    The first three requests have Error 401, whereas the last three requests are Status 200 前三个请求的错误为401,而后三个请求的状态为200

    On the Flask application instance on Cloud Run, only three requests are logged with Status 200.

    在Cloud Run上的Flask应用程序实例上,只有三个请求记录为Status 200 。

    Three requests are made to the Flask instance 向Flask实例发出了三个请求

    结论 (Conclusion)

    The process of .yaml configuration for Cloud Endpoint was a little bit confusing for me at first. I hope this article helps someone who is interested in deploying a web application on Cloud Run.

    .yaml ,我对Cloud Endpoint的.yaml配置过程有些困惑。 希望本文对有兴趣在Cloud Run上部署Web应用程序的人有所帮助。

    翻译自: https://medium.com/@tksh.nakamura/how-to-deploy-a-simple-flask-app-on-cloud-run-with-cloud-endpoint-e10088170eb7

    flask部署到云端

    相关资源:利用flask,kreas,把数字识别部署到云端
    Processed: 0.011, SQL: 8