Proxied 命令

proxied 命令是实现函数计算端云联调的命令。

相关原理

在 Serverless 架构下,由于部分资源是云产品并且通过 VPC 网络与业务逻辑建立关联,这就导致在开发过程中难以进行代码的调试,通过该命令可以通过代理的模式,将线上资源映射到本地,进而实现 VPC 网络下的本地调试能力。

端云联调的架构简图如上图所示,S 工具和通道服务进行的深度集成。

开启端云联调

用户只要在 s.yaml 的目录下, 执行 s proxied setup, 该命令做了如下事情:

  1. 根据您 s.yaml 的 vpc 配置等信息创建一个辅助的 Service/Function, 并对辅助函数预留1个实例。该辅助函数的作用是作为代理服务,本地实例所有进出流量都会通过该代理服务。

  2. 启动本地环境的代理容器实例,通过通道服务, 和 1 中的 FC 网络代理容器实例建立一条双向通信 TCP 隧道。

  3. 启动本地的函数容器实例,比如您是 Custom Runtime 直接跑 SpringBoot 应用, 启动 SpringBoot 的本地函数容器实例和 2 中的代理容器实例共享网络, springboot 应用已经能内网访问线上 VPC 资源。

  4. 本地函数容器实例启动成功,即可以开始调试,直接使用 s proxied invoke 或者 curl 自定义域名调用辅助的 Service/Function,流量会通过代理服务打回到本地函数容器实例, 开启本地 IDE 对实例内的应用进行断点调试。

关闭端云联调

因为会有一个辅助函数预留1个实例,所以调试结束后,您可以手动清理资源,以免产生不必要的费用

  1. 在开启端云联调的终端, 直接 CTRL + C 中断

  2. 或者在另外一个终端,在相同的目录下执行 s proxied cleanup

使用上面 1 或者 2 其中一个方法即可, 如果您不放心, 可以多次执行 s proxied cleanup

即使您忘记清理, 如果本地开发机关机或者断网, 通道 session 会自动关闭, 预留的资源也会自动清理。

命令解析

当执行命令proxied -h/proxied --help时,可以获取帮助文档。

在该命令中,包括了三个子命令:

proxied setup 命令

proxied setup 命令,是初始化/配置端云联调的命令。

当执行命令proxied setup -h/proxied setup --help时,可以获取帮助文档。

参数解析

参数全称参数缩写Yaml模式下必填参数含义
configc选填指定断点调试使用的 IDE,可选:vscode, intellij
debug-args-选填断点调试时传入的参数,详情见附录中的默认断点调试参数
debug-portd选填断点调试器端口
debugger-path-选填自定义断点调试器路径,会将本地指定路径挂载到程序运行环境的 /tmp/debugger_file 之中
tmp-dir-选填自定义函数运行环境中 /tmp 路径的本机挂载路径,默认为 ./.s/tmp/invoke/serviceName/functionName/

当前命令还支持部分全局参数(例如-a/--access, --debug等),详情可参考 Serverless Devs 全局参数文档

操作案例

有资源描述文件(Yaml)时,可以直接执行s proxied setup 开启端云联调模式,示例输出:

✔ Make service SESSION-S-d1564 success.
✔ Make function SESSION-S-d1564/python-event success.
Proxied resource setup succeeded.
> Next step tips: s proxied invoke

在开启端云联调之后,可以进行函数的触发,例如s proxied invoke,在使用过后,可以考虑清理相关辅助资源,例如s proxied cleanup

proxied invoke 命令

proxied invoke 命令,是进行端云联调函数触发/调用的命令。

当执行命令proxied invoke -h/proxied invoke --help时,可以获取帮助文档。

参数解析

参数全称参数缩写Yaml模式下必填Cli模式下必填参数含义
evente选填选填event 函数:传入的 event 事件数据,可以通过命令s cli fc-event快速获取事件,详细操作可以参考这里 ;
http 函数:传入的请求参数,格式可以参考 这里
event-filef选填选填event 参数内容以文件形式传入
event-stdins选填选填event 参数内容以标准输入流形式传入

当前命令还支持部分全局参数(例如-a/--access, --debug等),详情可参考 Serverless Devs 全局参数文档

操作案例

有资源描述文件(Yaml)时,可以通过s proxied invoke 对端云联调函数进行触发,例如 s proxied invoke -e '{}'

[2021-07-13T08:55:05.260] [INFO ] [S-CLI] - Start ...
========= FC invoke Logs begin =========
Not all function logs are available, please retry
FC Invoke End RequestId: bb720e13-e57a-4040-a920-82621e275ff1
Duration: 42.66 ms, Billed Duration: 43 ms, Memory Size: 512 MB, Max Memory Used: 40.85 MB
========= FC invoke Logs end =========

FC Invoke Result:
hello world

对于事件函数,需要先明确具体的事件类型(例如 OSS 事件, CDN 事件等),然后创建临时触发器,并将函数计算侧的目标函数和服务修改成生成的辅助 service/function( 比如proxied setup 命令操作过程中输出的SESSION-S-d1564/python-event),然后进行通过触发器即可直接触发函数获得端云联调的能力,例如如果是 OSS 创建 object 的事件,可以向指定的 OSS 中上传文件即可实现线上触发器触发本地函数的能力,即端云联调的能力。测试完成之后,不要忘记将临时指向生成的辅助资源的触发器恢复到原有的服务与函数资源上。

proxied cleanup 命令

proxied cleanup 命令,是对因端云联调而生成的辅助资源进行清理的命令。

当执行命令proxied cleanup -h/proxied cleanup --help时,可以获取帮助文档。

参数解析

当前命令支持部分全局参数(例如-a/--access, --debug等),详情可参考 Serverless Devs 全局参数文档

操作案例

有资源描述文件(Yaml)时,可以直接执行s proxied clean /s proxied cleanup对因端云联调而产生的辅助资源进行清理,示例输出:

Resource cleanup succeeded.

最佳实践

三步完成端云联调

端云联调可以通过三个非常简单的步骤快速实现:

  • 步骤1: 在已有的项目下,创建端云联调的辅助资源,开启端云联调模式:s proxied setup
  • 步骤2: 在完成端云联调模式开启动作之后,打开一个新的终端,通过s proxied invoke或者线上的事件进行函数的触发,调试;
  • 步骤3: 完成端云联调之后,通过s proxied cleanup命令,对因端云联调而产生的辅助资源进行清理;

断点调试

通过与常见的 IDE 进行结合,可以在常见的 IDE 上实现端云联调的断点调试。 目前端云联调断点调试支持三种语言: python、 nodejs 和 java, 非断点调试所有 runtime 均支持。

VSCode 断点调试案例

step1: 打开终端,进入目标项目下,输入启动指令开启调试模式的端云联调能力
$ s proxied setup --config vscode --debug-port 3000

命令执行完成功后, 本地的函数计算执行容器会阻塞等待调用(执行容器本质是一个 HTTP Server),与此同时当前项目会自动生成 .vscode/launch.json 文件,该文件是基于 VSCode 进行调试的配置文件,若该文件已经存在,那么启动指令会打印相应配置文本,需要利用这部分内容覆盖已有 .vscode/launch.json 中的内容。

step2: 启动调试器

打开 VSCode 界面,然后打开 s.yml 中 codeUri 所存放的源代码,为其打上断点,接着点击开始调试按钮,具体执行如下图所示。

step3: 发起对辅助函数的调用

打开一个新的终端,通过proxied invoke进行触发(例如s proxied invoke,如果是事件函数也可以通过线上触发器进行触发,此时要注意将触发器临时指向辅助函数,详情参考proxied invoke 命令操作过程),回到 VSCode 界面,既可以进行断点调试了:

img

调试完成后返回结果。

若要在调用的时候制定传入的 event 参数,可以使用 --event,例如s proxied invoke -h

step4: 结束调试
  1. 在开启端云联调的终端, 直接 CTRL + C 中断
  2. 或者在另外一个终端,在相同的目录下执行 s proxied cleanup

使用上面 1 或者 2 其中一个方法即可, 如果您不放心, 可以多次执行 s proxied cleanup

即使您忘记清理, 如果本地开发机关机或者断网, 通道 session 会自动关闭, 预留的资源也会自动清理。

断点调试实操视频
  • Event 函数 Watch the video

  • Http 函数 Watch the video

Intelli 断点调试案例

使用 Intellij 开发最多的语言是 Java,接下来我们将以本地调试 Java Event 函数为例,对“启动断点调试器”步骤进行详细说明。

step1:打开终端,进入目标项目下,输入启动指令

由于 Java 是编译型语言,因此在开始前需要对程序进行打包,本文示例会使用 mvn package 对函数打包

$ mvn package
$ s proxied setup --config intellij --debug-port 3000

命令执行完成功后, 本地的函数计算执行容器会阻塞等待调用(执行容器本质是一个 HTTP Server)

step2:启动断点调试器

此时若要进行断点调试,需要进行以下的操作在 IDEA 上进行相关的配置:

  1. 在菜单栏选择 Run… > Edit Configurations 。

img 2. 新建一个 Remote Debugging 。 img 3. 自定义调试器名称,并将端口配置为 3000 。 img 4. 上述配置完成后,在 IDEA 编辑器侧边栏为函数代码增加断点,点击"开始调试"按钮。 img

step3: 发起对辅助函数的调用

打开一个新的终端,通过proxied invoke进行触发(例如s proxied invoke,如果是事件函数也可以通过线上触发器进行触发,此时要注意将触发器临时指向辅助函数,详情参考proxied invoke 命令操作过程),回到 IDEA 界面,既可以进行断点调试了:

img

调试完成后返回结果。

若要在调用的时候制定传入的 event 参数,可以使用 --event,例如s proxied invoke -h

step4: 结束调试
  1. 在开启端云联调的终端, 直接 CTRL + C 中断
  2. 或者在另外一个终端,在相同的目录下执行 s proxied cleanup

使用上面 1 或者 2 其中一个方法即可, 如果您不放心, 可以多次执行 s proxied cleanup

即使您忘记清理, 如果本地开发机关机或者断网, 通道 session 会自动关闭, 预留的资源也会自动清理。

断点调试实操视频

Watch the video

权限与策略说明

  • proxied setup命令的权限,更多是和 要被端云联调的函数 Yaml 中所配置的参数有一定的关系,所以此处可以参考 Yaml 规范文档 中关于不同字段与权限的配置。

  • 除了基础配置之外,proxied 还需要以下策略作为支持:

    {
        "Statement": [
            {
                "Effect": "Allow",
                "Action": "tns:*",
                "Resource": "*"
            }
        ],
        "Version": "1"
    }
    
  • 如果使用proxied invoke命令,还需要对应的invoke权限,例如:

    • 最大权限: AliyunFCInvocationAccess 或者 AliyunFCFullAccess

    • 最小权限:

      {
          "Version": "1",
          "Statement": [
              {
                  "Action": "fc:InvokeFunction",
                  "Effect": "Allow",
                  "Resource": "acs:fc:<region>:<account-id>:services/<serviceName>.<qualifier>/functions/<functionName>"
              }
          ]
      }
      
  • 如果涉及到函数等相关辅助资源的清理,还需要对应的delete权限,例如:

    • 最大权限: AliyunFCInvocationAccess 或者 AliyunFCFullAccess

    • 最小权限参考:

      {
          "Statement": [
              {
                  "Action": [
                      "fc:ListOnDemandConfigs",
                      "fc:DeleteFunctionOnDemandConfig",
                      "fc:ListProvisionConfigs",
                      "fc:PutProvisionConfig",
                      "fc:ListAliases",
                      "fc:DeleteAlias",
                      "fc:ListServiceVersions",
                      "fc:DeleteServiceVersion",
                      "fc:ListTriggers",
                      "fc:DeleteTrigger",
                      "fc:ListFunctions",
                      "fc:DeleteFunction",
                      "fc:DeleteService"
                  ],
                  "Effect": "Allow",
                  "Resource": "*"
              }
          ],
          "Version": "1"
      }
      

实战场景举例

以阿里云函数计算一个真实的企业客户为例:小王是一个业务驱动型的公司的开发, 公司为了提高业务迭代效率, 技术架构向全面云原生化演进, 减少基本设施的管理和运维, 架构大致如下:

小王将迭代最频繁的对外的前后端分离的项目都一键迁移到函数计算的 Custom Runtime,在其中 SpringBoot 的项目需要能使用各种 VPC 内网地址访问下游服务(比如注册中心或者其他微服务接口), 这个时候Serverless Devs 提供的端云联调 就可以派上用场了, 只需要在 s.yaml (s.yaml 中定义了函数的 VPC 配置) 所在目录下执行:

$ s proxied setup

该命令会和云端 VPC 环境建立安全的网络通道,并在本地启动应用实例。此时本地实例可以无缝访问云端 VPC 环境内的资源,比如使用内网地址访问注册中心、RDS、 Kafka 等。这意味着您的应用配置不需要任何改变,就可以在本地和云端环境内的资源交互。

与此同时,直接使用这个SpringBoot后端项目对应在函数计算 FC 上的自定义域名,流量将被路由到本地应用实例上。比如,您的前端项目部署到 FC 的函数名字是 frontend, 对应的自定义域名是 frontend.abc.com。前端依赖的后端服务部署在 FC 上的函数名字是 backend,对应的自定义域名是 backend.abc.com。这个时候,您直接浏览器打开 fronted.abc.com,进行有后端请求的操作,流量就自动从线上路由到本地的 SpringBoot 实例,同时 SpringBoot 的日志在终端实时显示,甚至您也可以使用断点调试来自线上的流量。

假设本地启动 SpringBoot 后端项目的实例失败,可能的原因包括函数计算的 VPC 配置不对, 对应的下游服务有白名单限制等等。此时您在本地就可以重现和云端环境实例相同的启动过程,这对排查实例启动方面的问题极其有帮助。如下图所示:

我们从本地实例的启动过程信息就可以明确定位到原因是 Nacos 访问不通,我们需要查看函数是否正确配置了 Nacos 所在的 VPC 信息,或者 Nacos 是否有白名单限制等等。

附录

默认断点调试参数

RuntimeDefault Debug Args
nodejs 6--debug-brk=${debugPort}
nodejs 8/10/12/14--inspect-brk=0.0.0.0:${debugPort}
python 2.7/3/3.9-m debugpy --listen 0.0.0.0:${debugPort}
java 8-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,quiet=y,address=${debugPort}
java 11-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,quiet=y,address=*:${debugPort}
在 GitHub 上编辑本页面 更新时间: Fri, Nov 25, 2022