When you debug a function on your computer, you can use s proxied commands to invoke on-premises functions and cloud services. This mechanism is called cloud-terminal joint debugging. The cloud-terminal joint debugging feature helps improve development efficiency. This topic describes the basic principles of cloud-terminal joint debugging and uses examples to describe how to implement cloud-terminal joint debugging and breakpoint debugging. ApsaraDB RDS for MySQL and Apsara File Storage NAS (NAS) are used in the examples.

Usage notes

The cloud-terminal joint debugging feature supports only the x86_64 architecture and does not support the ARM64 architecture.

Principles

In the serverless field, debugging has always been a pain point for developers. Some cloud vendors have provided tools to solve this problem. However, these tools focus on simulating on-premises execution environments and parameters but cannot connect on-premises environments and online environments. Serverless Devs provides the cloud-terminal joint debugging feature, which enables the connection between on-premises and online environments.

duanyunliantiaoyuanlitupian
The preceding figure shows that Serverless Devs uses the ServiceConfig parameter information in the s.yaml file to create a helper function. The parameter information in the s.yaml file includes the configurations of virtual private clouds (VPCs) and NAS file storage. This way, the helper function (C) has identical service and network configurations as the debugging function. When the channel of cloud-terminal joint debugging is established, you can perform the following operations:
  • Access the resources of Alibaba Cloud public cloud from the container environment in which on-premises functions are invoked. For example, you can access the following environments:
    • VPC endpoints, such as the VPC endpoints of NAS, ApsaraDB RDS, or Message Queue for Apache Kafka
    • Internal networks, such as the internal endpoint of Object Storage Service (OSS)
  • Implement inbound traffic, such as the information about the context and event parameters. The inbound traffic represents the actual traffic from cloud services.

    You can directly use an SDK or a trigger to invoke the helper function (C). For example, you can use an SDK to run the invocation commands of cloud-terminal joint debugging. The request traffic is returned to the on-premises debugging instance (A). This instance is the container environment in which on-premises functions are executed. In this case, the inbound traffic is the actual traffic from the cloud.

Note A, B, and C in the preceding figure are all encapsulated in Serverless Devs. You need only to configure the resources in the code and s.yaml file based on your business requirements. The configurations of the code and the s.yaml file must meet the following requirements:
  • You must attach the code to an on-premises environment (A), which is the container environment in which on-premise functions are executed.
  • You can specify the port mapping between the integrated development environment (IDE) and the container environment by using the --debug-port parameter.

Sample code

Python 3 is used as an example in the following sample code. The following section provides examples to describe how to configure your function code and the s.yaml file. The examples are suitable for scenarios in which your code needs access ApsaraDB RDS for MySQL and NAS over a private network.
Sample code s.yaml example
# -*- coding: utf-8 -*-
import logging
import os
import pymysql
import pymysql.cursors

def handler(event, context):
    print("\n***test fc internal endpoint***")
    os.system("curl --connect-timeout 3 1.cn-hangzhou-internal.fc.aliyuncs.com")

    print("\n***test db internal addr ***")
    test_mysql()

    print("\n***test nas ***")
    os.system("ls -lh/mns/auto")

def test_mysql():
    # The private IP address of an ApsaraDB RDS for MySQL instance in VPC. 
    connection = pymysql.connect(host='rm-xxxxxxx.mysql.rds.aliyuncs.com',
                                 user='userName',
                                 password='userPwd',
                                 db='testDB',
                                 port=3306,
                                 charset='utf8')
    try:
        with connection.cursor() as cursor:
            sql = "select * from users"
            cout = cursor.execute(sql)
            print("total:"+str(cout))

            for row in cursor.fetchall():
                print("ID:"+str(row[0])+'  Name:'+row[1])
            connection.commit()

    finally:
        connection.close()                
edition: 1.0.0          #  The version of the YAML syntax. The version complies with the semantic versioning specification.
name: fcDeployApp       #  The name of the project.
access: "default"  #  The alias of the key.

services:
  fc-deploy-test: #  The name of the service.
    component: devsapp/fc  # The name of the component.
    props: #  The attribute value of the component.
      region: cn-hangzhou
      service:
        name: fc-deploy-service
        description: 'demo for proxied invoke'
        internetAccess: true
        vpcconfig:
            vpcId: vpc-bp1wv9al02opqahi****
            securityGroupId: sg-bp1h2swzeb5vgjfu****
            vswitchIds:
                - vsw-bp1kablus0jrcdeth****
        nasconfig:
            userId:10008
            groupId:10008
            mountPoints:
                - serverAddr: example.com
                nasDir: /
                fcDir: /mnt/auto
      function:
        name: event-function
        description: this is a test
        runtime: python3
        codeUri: .
        handler: index.handler
        memorySize: 128
        timeout: 60
Note After the channel for cloud-terminal joint debugging is established, you can debug the function on your computer. This way, you can access the VPC of Apsara RDS for MySQL and NAS over a private network in the code.

Prerequisites

The following operations are complete:

Procedure

  1. In the project directory, select one of the following commands based on your business requirements to prepare the helper resources and on-premises environment that are required for cloud-terminal joint debugging.
    • If only one project is contained in the s.yaml file, you do not need to specify a project for testing when you run the following command.
      s proxied setup
    • If multiple projects are contained in the s.yaml file, you must specify the project for testing when you run the following command:
      s <projectName> proxied setup
    Sample output:
    [2021-10-08T15:55:16.653] [INFO ] [S-CLI] - Start ...
      Session created, session id: S-d847ae28-767f-4532-a2f2-307ee2b99c5f.
    ......
    [2021-10-08T15:55:24.580] [INFO ] [FC-DEPLOY] - Checking Trigger httpTrigger exists
    [2021-10-08T15:55:24.807] [INFO ] [FC-DEPLOY] - Checking Trigger httpTrigger exists
      Make service SESSION-S-d847a success.// The helper service is deployed. 
      Make function SESSION-S-d847a/http-trigger-py36 success.// The helper function is deployed. 
      Make trigger SESSION-S-d847a/http-trigger-py36/httpTrigger success.// The helper trigger is deployed. 
    ......
    There is auto config in the service: SESSION-S-d847a
      Helper function is set to 1promise and 0elasticity.// The Function Compute (C) container is started. 
      Proxy container is running.// The code container in the on-premises environment (A) is started. 
      Session established! // The session is established. 
    [2021-10-08T15:56:13.251] [INFO ] [FC-PROXIED-INVOKE] - Pulling image registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-python3.6:1.9.19, you can also use 'docker pull registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-python3.6:1.9.19' to pull image by yourself.
    1.9.19: Pulling from aliyunfc/runtime-python3.6
    ......
    Digest: sha256:6a4da97962dba5f6cb00c5e8e83024c4758ec358e5bf884efff897b9826d9454
    Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-python3.6:1.9.19
    [2021-10-08T15:56:15.694] [INFO ] [FC-PROXIED-INVOKE] - Checking Server in function container is up. exists
    FunctionCompute python3 runtime inited.
    FC Invoke End RequestId: unknown_request_id, Error: Unhandled function error
    [2021-10-08T15:56:16.831] [INFO ] [FC-PROXIED-INVOKE] - Server in function container is up!// The execution environment of Function Compute in the on-premises environment (A) is started. 
    End of method: proxied
    Note After the command that you select is executed, the project is blocked and pending to be invoked. The execution environment is an HTTP server.
  2. Invoke the function.
    • HTTP function
      • If your function is an anonymous HTTP trigger function, you can use cURL or Postman to invoke the domain name that is temporally generated to implement on-premises debugging. cURL is used in this example.
        curl -v http://http-trigger-py36.SESSION-S-d847a.188077086902****.cn-hangzhou.fc.devsapp.net
      • If authType of the HTTP trigger is function, perform the following steps to implement debugging of the HTTP function:
        1. Start a new terminal.
        2. Run commands to switch to the project directory.
        3. Run the following command to invoke the function:
          s proxied invoke -e '{"body":123,"method":"GET","headers":{"key":"value"},"queries":{"key":"value"},"path":"string"}'
    • Event function
      • Event functions with triggers
        This example uses an OSS trigger to describe how to invoke a function in an on-premises environment.
        1. Confirm the trigger that you want to use to trigger function execution. The trigger can be an OSS trigger or CDN event trigger.
        2. Log on to the Function Compute console.
        3. Find the helper function and create a trigger for the function. For more information about how to create an OSS trigger in this example, see Step 1: Create an OSS trigger.
        4. Log on to the OSS console and trigger the event. For example, you can upload or download files to trigger the execution of the function in the on-premises execution environment.
      • Event functions without triggers
        Perform the following steps to invoke an event function that is not equipped with a trigger:
        1. Start a new terminal.
        2. Run commands to switch to the project directory.
        3. Run the following command to invoke the function:
          s proxied invoke -e '{"key":"value"}'
        Important If your event function is equipped with a trigger, you can also use this method to invoke this function in the on-premises environment.
  3. Run the following command to clean the resources and the on-premises environment that are required for cloud-terminal joint debugging.
    s proxied cleanup
    Sample output:
      Stop container succeed.
      Unset helper function provision and on-demand config done.
    [2021-10-08T16:41:19.960] [INFO ] [FC-DEPLOY] - Using region: cn-hangzhou
    [2021-10-08T16:41:19.988] [INFO ] [FC-DEPLOY] - Using access alias: default
    [2021-10-08T16:41:19.989] [INFO ] [FC-DEPLOY] - Using accessKeyID: LTAI4G4cwJkK4Rza6xd9****
    [2021-10-08T16:41:19.993] [INFO ] [FC-DEPLOY] - Using accessKeySecret: eCc0GxSpzfq1DVspnqqd6nmYNN****
    [2021-10-08T16:41:20.104] [INFO ] [FC-DEPLOY] - Checking Service SESSION-S-a9143 exists
    [2021-10-08T16:41:20.397] [INFO ] [FC-DEPLOY] - Service: SESSION-S-a9143 already exists online.
    [2021-10-08T16:41:20.400] [INFO ] [FC-DEPLOY] - Checking Function http-trigger-py36 exists
    [2021-10-08T16:41:20.583] [INFO ] [FC-DEPLOY] - Function: http-trigger-py36 already exists online.
    [2021-10-08T16:41:20.586] [INFO ] [FC-DEPLOY] - Checking Trigger httpTrigger exists
    [2021-10-08T16:41:20.820] [INFO ] [FC-DEPLOY] - Trigger: httpTrigger already exists online.
      Using fc deploy type: sdk, If you want to deploy with pulumi, you can [s cli fc-default set deploy-type pulumi] to switch.
      Delete trigger SESSION-S-a9143/http-trigger-py36/httpTrigger success.
      [TriggerNotFound], DELETE /services/SESSION-S-a9143/functions/http-trigger-py36/triggers/httpTrigger failed with 404. requestid: 9de742e1-d8f6-4db0-a4bd-02b10542147e, message: trigger 'httpTrigger' does not exist in service 'SESSION-S-a9143' and function 'http-trigger-py36'.
      Delete function SESSION-S-a9143/http-trigger-py36 success.
      Delete service SESSION-S-a9143 success.
      Delete session: S-a9143b1a-88ff-48bd-bd79-2f3755397fe2 done.
      Stop container succeed.
    End of method: proxied
    Note After the cleaning is complete, the blocking between the helper resources and the on-premises environment is removed.

Implement breakpoint debugging

The following section uses Python 3 as an example to describe how to implement breakpoint debugging during cloud-terminal joint debugging:

  1. Run the following command in the project directory to prepare the helper resources and on-premises environment that is required for cloud-terminal joint debugging.
    s proxied setup --config vscode --debug-port 3000 

    Sample command output:

    [2021-10-08T15:55:16.653] [INFO ] [S-CLI] - Start ...
      Session created, session id: S-d847ae28-767f-4532-a2f2-307ee2b99c5f.
    [2021-10-08T15:55:18.395] [INFO ] [FC-PROXIED-INVOKE] - Deploying helper function...
    [2021-10-08T15:55:18.397] [INFO ] [FC-PROXIED-INVOKE] - Creating cleaner service...
    [2021-10-08T15:55:22.021] [INFO ] [FC-DEPLOY] - Using region: cn-hangzhou
    [2021-10-08T15:55:22.022] [INFO ] [FC-DEPLOY] - Using access alias: default
    [2021-10-08T15:55:22.022] [INFO ] [FC-DEPLOY] - Using accessKeyID: LTAI4G4cwJkK4Rza6xd9****
    [2021-10-08T15:55:22.022] [INFO ] [FC-DEPLOY] - Using accessKeySecret: eCc0GxSpzfq1DVspnqqd6nmYNN****
     Using fc deploy type: sdk, If you want to deploy with pulumi, you can [s cli fc-default set deploy-type pulumi] to switch.
    [2021-10-08T15:55:22.971] [INFO ] [FC-DEPLOY] - Checking Service SESSION-S-d847a exists
    [2021-10-08T15:55:23.293] [INFO ] [FC-DEPLOY] - Setting role: AliyunFCDefaultRole
    [2021-10-08T15:55:23.886] [INFO ] [RAM] - Checking Role AliyunFCDefaultRole exists
    [2021-10-08T15:55:24.099] [INFO ] [RAM] - Updating role: AliyunFCDefaultRole
    [2021-10-08T15:55:24.191] [INFO ] [RAM] - Checking Plicy AliyunFCDefaultRolePolicy exists
    [2021-10-08T15:55:24.300] [INFO ] [FC-DEPLOY] - Checking Function http-trigger-py36 exists
    [2021-10-08T15:55:24.577] [WARN ] [FC-DEPLOY] - Image registry.cn-hangzhou.aliyuncs.com/aliyunfc/ts-remote:v0.1.1 dose not exist locally.
    Maybe you need to run 's build' first if it dose not exist remotely.
    [2021-10-08T15:55:24.580] [INFO ] [FC-DEPLOY] - Checking Trigger httpTrigger exists
    [2021-10-08T15:55:24.807] [INFO ] [FC-DEPLOY] - Checking Trigger httpTrigger exists
      Make service SESSION-S-d847a success.// The helper service is deployed. 
      Make function SESSION-S-d847a/http-trigger-py36 success.// The helper function is deployed. 
      Make trigger SESSION-S-d847a/http-trigger-py36/httpTrigger success.// The helper trigger is deployed. 
    [2021-10-08T15:55:26.129] [INFO ] [FC-DEPLOY] - Checking Service SESSION-S-d847a exists
    [2021-10-08T15:55:26.568] [INFO ] [FC-DEPLOY] - Checking Function http-trigger-py36 exists
    [2021-10-08T15:55:26.922] [INFO ] [FC-DEPLOY] - Checking Trigger httpTrigger exists
    [2021-10-08T15:55:27.542] [INFO ] [FC-DEPLOY] - Using customDomain: auto: fc will try to generate related custom domain resources automatically
      End of request
      Deployed.
      End of request
    [2021-10-08T15:55:35.499] [INFO ] [FC-DEPLOY] - Generated auto custom domain: http-trigger-py36.session-s-d847a.188077086902****.cn-hangzhou.fc.devsapp.net
    [2021-10-08T15:55:35.499] [INFO ] [FC-DEPLOY] - Creating custom domain: http-trigger-py36.session-s-d847a.188077086902****.cn-hangzhou.fc.devsapp.net
    [2021-10-08T15:55:35.679] [INFO ] [FC-DOMAIN] - Creating custom domain: http-trigger-py36.session-s-d847a.188077086902****.cn-hangzhou.fc.devsapp.net
    
    There is auto config in the service: SESSION-S-d847a
      Helper function is set to 1promise and 0elasticity.// The Function Compute (C) container is started. 
      Proxy container is running.// The code container in the on-premises environment (A) is started. 
      Session established! // The session is established. 
    [2021-10-08T15:56:13.251] [INFO ] [FC-PROXIED-INVOKE] - Pulling image registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-python3.6:1.9.19, you can also use 'docker pull registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-python3.6:1.9.19' to pull image by yourself.
    1.9.19: Pulling from aliyunfc/runtime-python3.6
    ......
    Digest: sha256:6a4da97962dba5f6cb00c5e8e83024c4758ec358e5bf884efff897b9826d9454
    Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-python3.6:1.9.19
    [2021-10-08T15:56:15.694] [INFO ] [FC-PROXIED-INVOKE] - Checking Server in function container is up. exists
    FunctionCompute python3 runtime inited.
    FC Invoke End RequestId: unknown_request_id, Error: Unhandled function error
    [2021-10-08T15:56:16.831] [INFO ] [FC-PROXIED-INVOKE] - Server in function container is up!// The execution environment of Function Compute in the on-premises environment (A) is started. 
    End of method: proxied

    After the command is executed, the project is blocked and pending to be invoked. If you directly run the invocation command, the function is invoked in an on-premises environment. If breakpoint debugging is required, add a breakpoint (①) to the code of a function in the sidebar of the VS Code editor, and then click the debugging icon (②).

  2. Start a new terminal and run the following command to invoke the function.
    s proxied invoke

    After you run the debugging command, go back to the VS Code interface. Breakpoint debugging is started for the function.

  3. Run the following command to clean the helper resources, sessions, and on-premises debugging container:
    s proxied clean

The following sample Java 8 code describes how to use IntelliJ IDEA to implement breakpoint debugging:

  1. Run the following command in the project directory to install dependencies:
    s build --use-docker

    Sample command output:

    [2021-10-09T15:28:39.391] [INFO ] [S-CLI] - Start ...
    [2021-10-09T15:28:40.520] [INFO ] [FC-BUILD] - Build artifact start...
    [2021-10-09T15:28:40.548] [INFO ] [FC-BUILD] - Use docker for building.
    [2021-10-09T15:28:40.867] [INFO ] [FC-BUILD] - Build function using image: registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-java8:build-1.9.21
    [2021-10-09T15:28:41.411] [INFO ] [FC-BUILD] - begin pulling image registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-java8:build-1.9.21, you can also use docker pull registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-java8:build-1.9.21 to pull image by yourself.
    build-1.9.21: Pulling from aliyunfc/runtime-java8
    ......
    Digest: sha256:35eb46f6235729dbcb1fa48f4ce4ae7b213b967a0f1b9c625e464dbba58af22d
    Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/aliyunfc/runtime-java8:build-1.9.21
    [2021-10-09T15:30:52.690] [INFO ] [FC-BUILD] - Build artifact successfully.
    
    Tips for next step
    ======================
    * Invoke Event Function: s local invoke
    * Invoke Http Function: s local start
    * Deploy Resources: s deploy
    End of method: build

  2. Run the following command to prepare helper resources and the on-premises environment that are required for cloud-terminal joint debugging.
    s proxied setup --debug-port 3000 

    After the command is executed, the project is blocked and pending to be invoked. If you directly run the invocation command, the function is invoked in the on-premises environment. If you require breakpoint debugging, you must configure IntelliJ IDEA when you perform breakpoint debugging for the first time.

    1. Open IntelliJ IDEA, and then open the corresponding project directory. In the top navigation bar of IntelliJ IDEA, choose Run > Debug Configurations.
    2. In the Run/Debug Configurations dialog box, click the plus icon and select Remote to configure the parameters:
      • Name: the name of the custom debugger.
      • Port: the port number. Set the value to 3000. If you set --debug-port to another port number for cloud-terminal joint debugging, set Port to the same port number as that of --debug-port.
    3. Click ok. The IntelliJ IDEA configuration is complete.

  3. Add a breakpoint for the code of a function in the sidebar of the IDEA editor (①) and click the debug icon (②).
  4. Start a new terminal and run the following command to invoke the function.
    s proxied invoke

    After you run the debugging command, go back to the IntelliJ IDEA interface. Breakpoint debugging is started for the function.

  5. Run the following command to clean the helper resources, sessions, and on-premises debugging container:
    s proxied clean