OpenFaaS梳理之三:OpenFaaS API Gateway

本文是《OpenFaaS梳理》系列的第三篇,在前面两节搭建openfaas部署环境并且成功将一个函数发布到openfaas之后,我们就可以通过前端页面进行已经发布函数信息的查看,其中包括已经发布的函数列表以及对单个函数通过Invoke function 以request请求进行测试,类似于postman进行访问。不过身为开发人员当然不止想通过工具进行访问,官方提供了OpenFaaS API Gateway 通过接口进行openfaas对函数从部署(deploy)、触发(invoke)、扩缩容(scale)等操作,本篇的是通过研究熟悉OpenFaaS API Gateway进行函数的相关操作。

目录

OpenFaaS Gateway

 Swagger.yml

Swagger接口

0.首先是demo的一些基本常量

1.查看发布函数的详细信息

2.查看发布函数的详细信息

3.发布函数

4.触发函数


OpenFaaS Gateway

官方连接:OpenFaaS API Gateway / Portal

官方的介绍: Gateway 是一个路径,通过该路径用户可以通过对Prometheus的访问,对已经发布的函数进行监控;同时,gateway提供了一个UI界面,在该界面用户可以管理已经发布的函数,同时该界面进行触发测试。

此外,Gateway 通过 Kubernetes的API命令修改服务的副本数,实现对已经发布服务的扩缩容。

总之,Gateway具有如下作用:
1.它是openfaas内置的UI界面
2.通过它,可以从Function Store部署函数或触发已经发布的函数
3.通过Prometheus对函数进行监控
4.通过AlertManager和Prometheus实现服务的自动扩缩容
5.提供Swagger提供REST API

 Swagger.yml

上图中,介绍到官方提供了对Gateway的访问的swagger.yaml,我们通过在线编辑器进行打开,可以看到官方提供了很多的方法进行对接口的访问。

在线编辑器:swaggerIO

Swagger接口

下面我们挑选几个接口进行测试(由于该接口都是get和post接口,本文写了一个工具类管理基本的get和post请求,请参见最后):

0.首先是demo的一些基本常量

    private static Logger logger = LoggerFactory.getLogger(OpenfaasFunctionDemo.class);
    private static final String BASICAUTH = "admin:openfaas";
    private static final String OPENFAAS_URL = "http://192.168.79.139:31112/";
    private static final String SCALE_FUNCTION = "system/scale-function";
    private static final String SYSTEM_FUNCTION = "system/function";
    private static final String SYSTEM_FUNCTIONS = "system/functions";
    private static final String SYSTEM_LOGS = "system/logs";
    private static final String BACKSLASH = "/";

其中最重要的是BASICAUTH 是openfaas的用户名和密码;OPENFAAS_URL是openfaas gateway的访问地址;

1.查看发布函数的详细信息

 代码段:

    /**
     * 获取所有的函数列表
     */
    public static void listFunctionGet() {
        String url = OPENFAAS_URL + SYSTEM_FUNCTIONS;
        String data = HttpClientUtils.httpGet(url, BASICAUTH);
        System.out.println("遍历服务列表:" + data);
    }

测试返回结果:

[
  {
    "name": "add-demo",
    "image": "192.168.79.131:8443/openfaas/add-demo:latest",
    "namespace": "openfaas-fn",
    "envProcess": "python index.py",
    "labels": {
      "faas_function": "add-demo"
    },
    "annotations": {
      "prometheus.io.scrape": "false"
    },
    "replicas": 1,
    "availableReplicas": 1,
    "createdAt": "2022-09-16T14:41:32Z"
  },
  {
    "name": "test-deploy-sync",
    "image": "192.168.79.131:8443/openfaas/add-demo:latest",
    "namespace": "openfaas-fn",
    "labels": {
      "faas_function": "test-deploy-sync"
    },
    "annotations": {
      "prometheus.io.scrape": "false"
    },
    "limits": {
      "memory": "256M",
      "cpu": "1"
    },
    "requests": {
      "memory": "256M",
      "cpu": "1"
    },
    "invocationCount": 1,
    "replicas": 1,
    "availableReplicas": 1,
    "createdAt": "2022-09-21T11:51:21Z"
  }
]

2.查看发布函数的详细信息

代码段:

    /**
     * 启动函数
     * @param serviceName
     */
    public static void startFunctionPost(String serviceName) {
        HashMap<String, Object> param = new HashMap<>();
        int instances = 2;
        param.put("service", serviceName);
        param.put("replicas", instances);
        String url = OPENFAAS_URL + SCALE_FUNCTION + BACKSLASH + serviceName;
        String result = HttpClientUtils.httpPostByBody(url, param, BASICAUTH);
        System.out.println("启动服务结果:" + result);
    }

    /**
     * 停止函数
     * @param serviceName
     */
    public static void stopFunctionPost(String serviceName) {
        HashMap<String, Object> param = new HashMap<>();
        int instances = 0;
        param.put("service", serviceName);
        param.put("replicas", instances);
        String url = OPENFAAS_URL + SCALE_FUNCTION + BACKSLASH + serviceName;
        String result = HttpClientUtils.httpPostByBody(url, param, BASICAUTH);
        System.out.println("停止服务结果:" + result);
    }

其实质就是通过调用  system/scale-function 接口进行扩缩容改变实例的数量,进行函数的启停。

3.发布函数

代码段:

   /**
     * 部署触发器函数
     *
     * @param serviceName
     * @param imageFullName
     * @param cpu
     * @param memory
     * @param timeOut
     * @param instances
     */
    public static void deploySyncFunctionPost(String serviceName, String imageFullName, String cpu, String memory, String timeOut, String instances) {
        HashMap<String, Object> param = new HashMap<>();
        HashMap<String, Object> requestParam = new HashMap<>();
        HashMap<String, Object> labelsParam = new HashMap<>();
        HashMap<String, Object> limitsParam = new HashMap<>();

        requestParam.put("memory", memory + "M");
        requestParam.put("cpu", cpu);
        limitsParam.put("memory", memory + "M");
        limitsParam.put("cpu", cpu);

        param.put("service", serviceName);
        param.put("image", imageFullName);
        param.put("limits", limitsParam);
        param.put("requests", requestParam);

        labelsParam.put("com.openfaas.scale.min", instances);
        param.put("label", labelsParam);

        HashMap<Object, Object> envVarsMap = new HashMap<>();
        envVarsMap.put("userName", "hello");
        param.put("envVars", envVarsMap);
        param.put("replicas", instances);
        //http://192.168.79.139:31112/system/functions
        String url = OPENFAAS_URL + SYSTEM_FUNCTIONS;
        String result = HttpClientUtils.httpPostByBody(url, param, BASICAUTH);
        System.out.println("启动同步服务: " + result);
    }


    /**
     * 测试部署函数
     */
    public static void testDeployFunction() {
        String serviceName = "test-deploy-sync";
        String imageFullName = "192.168.79.131:8443/openfaas/add-demo:latest";
        String envVars = "";
        String cpu = "1";
        String memory = "256";
        String timeOut = "3000";
        String instance = "2";
        deploySyncFunctionPost(serviceName, imageFullName, cpu, memory, timeOut, instance);
    }

发布后再前端可见:

4.触发函数

 

代码段:

    public static void invokeFunctionPost(String serviceName,String msg) {
        HashMap<String, Object> param = new HashMap<>();
        param.put("name", serviceName);
        param.put("hello", msg);
        // http://192.168.79.139:31112/system/logs
        String url = OPENFAAS_URL + FUNCTION + BACKSLASH + serviceName;
        String data = HttpClientUtils.httpGet(url, param, BASICAUTH);
        System.out.println("获取日志" + data);
    }

 返回结果:

 由于时间有限,针对gatewayapi的测试访问就到这里,后面有机会再补充其他功能接口的测试。

完整代码

HttpClientUtils: 
package com.openfaas.utils;

import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.nio.charset.StandardCharsets;
import java.util.*;

public class HttpClientUtils {
    /**
     * 将传入的键值对转化为NameValuePair参数集
     *
     * @param paramsMap
     * @return
     */
    private static List<NameValuePair> getParamList(Map<String, Object> paramsMap) {
        if (paramsMap == null || paramsMap.size() == 0) {
            return Collections.emptyList();
        }
        ArrayList<NameValuePair> params = new ArrayList<>();
        for (Map.Entry<String, Object> set : paramsMap.entrySet()) {
            String key = set.getKey();
            if (key != null) {
                String value = set.getValue() == null ? "" : set.getValue().toString();
                params.add(new BasicNameValuePair(key, value));
            }
        }
        return params;
    }

    public static String httpGet(String url, String basicAuth){
        return httpGet(url,new HashMap<>(),String.valueOf(StandardCharsets.UTF_8),basicAuth);
    }

    public static String httpGet(String url, Map<String, Object> params, String basicAuth) {
        return httpGet(url,params,String.valueOf(StandardCharsets.UTF_8),basicAuth);
    }

    public static String httpGet(String url, Map<String, Object> params, String charset, String basicAuth) {
        if (StringUtils.isBlank(url)) {
            return null;
        }

        List<NameValuePair> gparams = getParamList(params);
        if (gparams != null && gparams.size() > 0) {
            charset = charset == null ? String.valueOf(StandardCharsets.UTF_8) : charset;
            String formatParams = URLEncodedUtils.format(gparams, charset);
            url = url.indexOf("?") < 0 ? (url + "?" + formatParams) : (url.substring(0, url.indexOf("?") + 1) + formatParams);
        }

        String responseBody = null;
        HttpClient httpClient = null;
        HttpGet httpGet = null;
        try {
            if (url.startsWith("https")) {
//                httpClient = new SSLClinet();
            } else {
                httpClient = new DefaultHttpClient();
            }
            httpGet = new HttpGet(url);

            RequestConfig config = RequestConfig.custom().setConnectTimeout(50000).build();
            httpGet.setConfig(config);

            if (StringUtils.isNotBlank(basicAuth)) {
                httpGet.setHeader(HttpHeaders.AUTHORIZATION,
                        "Basic " + new String(Base64.getEncoder().encode(basicAuth.getBytes(StandardCharsets.UTF_8))));
            }

            HttpResponse response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                responseBody = EntityUtils.toString(entity);
            }
            EntityUtils.consume(entity);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            abortConnection(httpGet, httpClient);
        }
        return responseBody;
    }

    public static String httpPostByBody(String url, Map<String, Object> requestBodyMap, String basicAuth) {
        String body = null;
        HttpClient httpClient = null;
        HttpPost httpPost = null;
        try {
            if (url.startsWith("https")) {
//                httpClient = new SSLClinet();
            } else {
                httpClient = new DefaultHttpClient();
            }
            httpPost = new HttpPost(url);
            // 添加body
            if (requestBodyMap != null) {
                String requestBody = JSON.toJSONString(requestBodyMap);
                System.out.println("requestBody:" + requestBody);
                ByteArrayEntity arrayEntity = new ByteArrayEntity(requestBody.getBytes(StandardCharsets.UTF_8));
                arrayEntity.setContentType("application/json");
                httpPost.setEntity(arrayEntity);
            }

            if (StringUtils.isNotBlank(basicAuth)) {
                httpPost.setHeader(HttpHeaders.AUTHORIZATION,
                        "Basic " + new String(Base64.getEncoder().encode(basicAuth.getBytes(StandardCharsets.UTF_8))));
            }

            HttpResponse response = httpClient.execute(httpPost);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                body = EntityUtils.toString(entity);
            }
            EntityUtils.consume(entity);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            abortConnection(httpPost, httpClient);
        }
        return body;
    }

    public static String httpDeleteByBody(String url, Map<String, Object> requestBodyMap, String basicAuth) {
        String body = null;
        HttpClient httpClient = null;
        MineHttpDelete httpDelete = null;
        try {
            if (url.startsWith("https")) {
//                httpClient = new SSLClinet();
            } else {
                httpClient = new DefaultHttpClient();
            }
            httpDelete = new MineHttpDelete(url);
            // 添加body
            if (requestBodyMap != null) {
                String requestBody = JSON.toJSONString(requestBodyMap);
                System.out.println("requestBody:" + requestBody);
                ByteArrayEntity arrayEntity = new ByteArrayEntity(requestBody.getBytes(StandardCharsets.UTF_8));
                arrayEntity.setContentType("application/json");
                httpDelete.setEntity(arrayEntity);
            }

            if (StringUtils.isNotBlank(basicAuth)) {
                httpDelete.setHeader(HttpHeaders.AUTHORIZATION,
                        "Basic" + new String(Base64.getEncoder().encode(basicAuth.getBytes(StandardCharsets.UTF_8))));
            }

            HttpResponse response = httpClient.execute(httpDelete);
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                body = EntityUtils.toString(entity);
            }
            EntityUtils.consume(entity);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            abortConnection(httpDelete, httpClient);
        }
        return body;
    }
    /**
     * 释放
     *
     * @param httpPost
     * @param httpClient
     */
    private static void abortConnection(HttpRequestBase httpPost, HttpClient httpClient) {
        if (httpPost != null) {
            httpPost.abort();
        }
        if (httpClient != null) {
            httpClient.getConnectionManager().shutdown();
        }
    }
}

 OpenfaasFunctionDemo:

package com.openfaas;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.openfaas.utils.HttpClientUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;

public class OpenfaasFunctionDemo {

    private static Logger logger = LoggerFactory.getLogger(OpenfaasFunctionDemo.class);
    private static final String BASICAUTH = "admin:openfaas";
    private static final String OPENFAAS_URL = "http://192.168.79.139:31112/";
    private static final String SCALE_FUNCTION = "system/scale-function";
    private static final String SYSTEM_FUNCTION = "system/function";
    private static final String FUNCTION = "function";
    private static final String SYSTEM_FUNCTIONS = "system/functions";
    private static final String SYSTEM_LOGS = "system/logs";
    private static final String BACKSLASH = "/";


    /**
     * 获取所有的函数列表
     */
    public static void listFunctionGet() {
        String url = OPENFAAS_URL + SYSTEM_FUNCTIONS;
        String data = HttpClientUtils.httpGet(url, BASICAUTH);
        System.out.println("遍历服务列表:" + data);
    }

    /**
     * 启动函数
     * @param serviceName
     */
    public static void startFunctionPost(String serviceName) {
        HashMap<String, Object> param = new HashMap<>();
        int instances = 2;
        param.put("service", serviceName);
        param.put("replicas", instances);
        String url = OPENFAAS_URL + SCALE_FUNCTION + BACKSLASH + serviceName;
        String result = HttpClientUtils.httpPostByBody(url, param, BASICAUTH);
        System.out.println("启动服务结果:" + result);
    }

    /**
     * 停止函数
     *
     * @param serviceName
     */
    public static void stopFunctionPost(String serviceName) {
        HashMap<String, Object> param = new HashMap<>();
        param.put("service", serviceName);
        param.put("replicas", 0);
        String url = OPENFAAS_URL + SCALE_FUNCTION + BACKSLASH + serviceName;
        String result = HttpClientUtils.httpPostByBody(url, param, BASICAUTH);
        System.out.println("停止服务结果:" + result);
    }

    /**
     * 删除函数
     *
     * @param serviceName
     */
    public static void deleteFunctionPost(String serviceName) {
        HashMap<String, Object> param = new HashMap<>();
        param.put("service", serviceName);
        String url = OPENFAAS_URL + SCALE_FUNCTION;
        String result = HttpClientUtils.httpDeleteByBody(url, param, BASICAUTH);
        System.out.println("删除服务结果:" + result);
    }

    /**
     * 获取服务状态
     *
     * @param serviceName
     */
    public static void getFunctionStatus(String serviceName) {
        String url = OPENFAAS_URL + SYSTEM_FUNCTION + BACKSLASH + serviceName;
        String data = HttpClientUtils.httpGet(url, BASICAUTH);
        System.out.println("data:" + data);
        JSONObject jsonObject = JSON.parseObject(data);
        if (jsonObject != null && jsonObject.containsKey("replicas") && jsonObject.containsKey("availableReplicas")) {
            int availableReplicas = jsonObject.getInteger("availableReplicas");
            if (availableReplicas > 0) {
                System.out.println("服务状态:已经启动。");
            } else {
                System.out.println("服务状态:未启动。");
            }
        } else {
            System.out.println("服务状态:未启动。");
        }
        if (StringUtils.isNotBlank(data)) {
            System.out.println("服务状态:" + data);
        }
    }

    /**
     * 部署触发器函数
     *
     * @param serviceName
     * @param imageFullName
     * @param cpu
     * @param memory
     * @param timeOut
     * @param instances
     */
    public static void deploySyncFunctionPost(String serviceName, String imageFullName, String cpu, String memory, String timeOut, String instances) {
        HashMap<String, Object> param = new HashMap<>();
        HashMap<String, Object> requestParam = new HashMap<>();
        HashMap<String, Object> labelsParam = new HashMap<>();
        HashMap<String, Object> limitsParam = new HashMap<>();

        requestParam.put("memory", memory + "M");
        requestParam.put("cpu", cpu);
        limitsParam.put("memory", memory + "M");
        limitsParam.put("cpu", cpu);

        param.put("service", serviceName);
        param.put("image", imageFullName);
        param.put("limits", limitsParam);
        param.put("requests", requestParam);

        labelsParam.put("com.openfaas.scale.min", instances);
        param.put("label", labelsParam);

        HashMap<Object, Object> envVarsMap = new HashMap<>();
        envVarsMap.put("userName", "hello");
        param.put("envVars", envVarsMap);
        param.put("replicas", instances);
        //http://192.168.79.139:31112/system/functions
        String url = OPENFAAS_URL + SYSTEM_FUNCTIONS;
        String result = HttpClientUtils.httpPostByBody(url, param, BASICAUTH);
        System.out.println("启动同步服务: " + result);
    }


    /**
     * 测试部署函数
     */
    public static void testDeployFunction() {
        String serviceName = "test-deploy-sync";
        String imageFullName = "192.168.79.131:8443/openfaas/add-demo:latest";
        String envVars = "";
        String cpu = "1";
        String memory = "256";
        String timeOut = "3000";
        String instance = "2";
        deploySyncFunctionPost(serviceName, imageFullName, cpu, memory, timeOut, instance);
    }


    /**
     * 获取部署函数的日志
     *
     * @param serviceName
     */
    public static void getFunctionLogsPost(String serviceName) {
        HashMap<String, Object> param = new HashMap<>();
        param.put("name", serviceName);
        param.put("tail", Long.MAX_VALUE);
        // http://192.168.79.139:31112/system/logs
        String url = OPENFAAS_URL + SYSTEM_LOGS;
        String data = HttpClientUtils.httpGet(url, param, BASICAUTH);
        System.out.println("获取日志" + data);
    }


    public static void invokeFunctionPost(String serviceName,String msg) {
        HashMap<String, Object> param = new HashMap<>();
        param.put("name", serviceName);
        param.put("hello", msg);
        // http://192.168.79.139:31112/system/logs
        String url = OPENFAAS_URL + FUNCTION + BACKSLASH + serviceName;
        String data = HttpClientUtils.httpGet(url, param, BASICAUTH);
        System.out.println("获取日志" + data);
    }


    public static void main(String[] args) {
        String serviceName = "add-demo";
        String message = "陌生人";
//        listFunctionGet();
//        startFunctionPost(serviceName);
//        getFunctionLogsPost(serviceName);

//        getFunctionStatus(serviceName);
//        testDeployFunction();

        invokeFunctionPost(serviceName,message);
    }

}

总结

本篇介绍了openfaas的gateway下的api接口提供的功能及简单的访问,实现了函数发布和触发等功能接口的调用。对于原理并未深究,感兴趣的同学可以参考以下文章进行了解。

OpenFaaS实战之一:部署

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值