关于云计算:OpenFaaS实战之三Java函数

8次阅读

共计 7981 个字符,预计需要花费 20 分钟才能阅读完成。

欢送拜访我的 GitHub

https://github.com/zq2599/blog_demos

内容:所有原创文章分类汇总及配套源码,波及 Java、Docker、Kubernetes、DevOPS 等;

OpenFaaS 实战系列文章链接

  1. 部署
  2. 函数入门
  3. Java 函数
  4. 模板操作 (template)
  5. 大话 watchdog
  6. of-watchdog(为性能而生)
  7. java11 模板解析
  8. OpenFaaS 实战之八:自制模板 (maven+jdk8)
  9. OpenFaaS 实战之九:终篇,自制模板 (springboot+maven+jdk8)

本篇概览

  1. 本文是《OpenFaaS 实战》系列的第三篇,通过前文实战,咱们把握了函数开发和部署的要领,作为一名 Java 程序员,当然迫切的心愿用 Java 编写 OpenFaaS 函数,于是就有了本文;
  2. 本文开发一个 Java 函数,性能是解析申请 body 中的 JSON 字符串,再加上 JVM 过程 ID、IP 地址、以后工夫一起拼成字符串,包装在 JSON 中返回;
  3. 平时写 java 代码会用到各种二方库,这里引入 jackson 的库,作为 OpenFaaS 增加依赖的参考;

源码下载

  • 本篇实战中的源码可在 GitHub 下载到,地址和链接信息如下表所示 (https://github.com/zq2599/blo…
名称 链接 备注
我的项目主页 https://github.com/zq2599/blo… 该我的项目在 GitHub 上的主页
git 仓库地址 (https) https://github.com/zq2599/blo… 该我的项目源码的仓库地址,https 协定
git 仓库地址 (ssh) git@github.com:zq2599/blog_demos.git 该我的项目源码的仓库地址,ssh 协定
  • 这个 git 我的项目中有多个文件夹,本章的利用在 <font color=”blue”>openfaas</font> 文件夹下,如下图红框所示:

  • <font color=”blue”>openfaas</font> 外面有多个子文件夹,本篇的源码在 <font color=”blue”>currenttime</font> 中,如下图红框:

创立函数

  1. 执行以下命令,即可创立名为 <font color=”blue”>faas-currenttime</font> 的函数,此函数的镜像前缀是 <font color=”blue”>bolingcavalry</font>,语言类型为 <font color=”red”>java11</font>:
faas-cli new faas-currenttime --lang java11 -p bolingcavalry
  1. 控制台响应如下:
[root@node1 20]# faas-cli new faas-currenttime --lang java11 -p bolingcavalry
2020/11/20 15:47:50 No templates found in current directory.
2020/11/20 15:47:50 Attempting to expand templates from https://github.com/openfaas/templates.git

2020/11/20 15:47:56 Fetched 12 template(s) :  from https://github.com/openfaas/templates.git
Folder: faas-currenttime created.
  ___                   _____           ____
 / _ \ _ __   ___ _ __ |  ___|_ _  __ _/ ___|
| | | | '_ \ / _ \'_ \| |_ / _` |/ _` \___ \
| |_| | |_) |  __/ | | |  _| (_| | (_| |___) |
 \___/| .__/ \___|_| |_|_|  \__,_|\__,_|____/
      |_|


Function created in folder: faas-currenttime
Stack file written: faas-currenttime.yml

Notes:
You have created a function using the java11 template which uses an LTS
version of the OpenJDK.
  1. 当前目录曾经新增了文件 <font color=”blue”>faas-currenttime.yml</font> 和文件夹 <font color=”blue”>faas-currenttime</font>
  2. 文件夹 <font color=”blue”>faas-currenttime</font> 的内容如下,可见是个 gradle 工程:
faas-currenttime
├── build.gradle
├── gradle
│   └── wrapper
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── settings.gradle
└── src
    ├── main
    │   └── java
    │       └── com
    │           └── openfaas
    │               └── function
    │                   └── Handler.java
    └── test
        └── java
            └── HandlerTest.java
  1. 关上 <font color=”red”>build.gradle</font> 文件,增加下图红框中的内容,即 <font color=”blue”>jackson</font> 和 <font color=”blue”>common</font> 库的依赖:

  1. 进入文件夹 <font color=”blue”>faas-currenttime/src/main/java/com/openfaas/function/</font>,可见已创立了默认的业务性能类 <font color=”red”>Handler.java</font>,关上看看 OpenFaaS 给的默认代码啥样的,如下所示:
package com.openfaas.function;

import com.openfaas.model.IHandler;
import com.openfaas.model.IResponse;
import com.openfaas.model.IRequest;
import com.openfaas.model.Response;

public class Handler extends com.openfaas.model.AbstractHandler {public IResponse Handle(IRequest req) {Response res = new Response();
            res.setBody("Hello, world!");

            return res;
    }
}
  1. 把 Handler.java 的内容用以下代码替换掉,替换后的函数,其性能是获得申请参数,再把以后 JVM 的过程 ID、IP 地址、以后工夫都拼接到一个字符串中返回,须要重点关注的有两点:将申请参数反序列化成 Map 实例,以及将 Map 序列化成 JSON 字符串返回:
package com.openfaas.function;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.openfaas.model.IRequest;
import com.openfaas.model.IResponse;
import com.openfaas.model.Response;
import org.apache.commons.lang3.StringUtils;

import java.lang.management.ManagementFactory;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

public class Handler extends com.openfaas.model.AbstractHandler {

    private static final String PARAM_USER_NAME = "name";


    private static final String RESPONSE_TEMPLETE = "Hello %s, response from [%s], PID [%s], %s";

    private ObjectMapper mapper = new ObjectMapper();


    /**
     * 获取本机 IP 地址
     * @return
     */
    public static String getIpAddress() {
        try {Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
            InetAddress ip = null;
            while (allNetInterfaces.hasMoreElements()) {NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
                if (netInterface.isLoopback() || netInterface.isVirtual() || !netInterface.isUp()) {continue;} else {Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
                    while (addresses.hasMoreElements()) {ip = addresses.nextElement();
                        if (ip != null && ip instanceof Inet4Address) {return ip.getHostAddress();
                        }
                    }
                }
            }
        } catch (Exception e) {System.err.println("IP 地址获取失败" + e.toString());
        }
        return "";
    }

    /**
     * 返回以后过程 ID
     * @return
     */
    private static String getPID() {
        return ManagementFactory
                .getRuntimeMXBean()
                .getName()
                .split("@")[0];
    }


    private String getUserName(IRequest req) {
        // 如果从申请 body 中取不到 userName,就用
        String userName = null;

        try {Map<String, Object> mapFromStr = mapper.readValue(req.getBody(),
                    new TypeReference<Map<String, Object>>() {});

            if(null!=mapFromStr && mapFromStr.containsKey(PARAM_USER_NAME)) {userName = String.valueOf(mapFromStr.get(PARAM_USER_NAME));
            }

        } catch (Exception e) {e.printStackTrace();
        }

        // 如果从申请 body 中取不到 userName,就给个默认值
        if(StringUtils.isBlank(userName)) {userName = "anonymous";}

        return userName;
    }

    public IResponse Handle(IRequest req) {String userName = getUserName(req);

        System.out.println("1. ---" + userName);

        // 返回信息带上以后 JVM 所在机器的 IP、过程号、工夫
        String message = String.format(RESPONSE_TEMPLETE,
                userName,
                getIpAddress(),
                getPID(),
                new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date()));

        System.out.println("2. ---" + message);

        // 响应内容也是 JSON 格局,所以先存入 map,而后再序列化
        Map<String, Object> rlt = new HashMap<>();
        rlt.put("success", true);
        rlt.put("message", message);

        String rltStr = null;

        try {rltStr = mapper.writeValueAsString(rlt);
        } catch (Exception e) {e.printStackTrace();
        }

        Response res = new Response();
        res.setContentType("application/json;charset=utf-8");
        res.setBody(rltStr);

        return res;
    }
}
  • 至此编码实现,接下来是制作镜像和部署;

部署

  1. 在 <font color=”blue”>faas-currenttime.yml</font> 所在目录执行以下命令,即可开始制作镜像,制作过程中会有 gradle 的编译过程,如果编译失败会中断镜像制作:
faas-cli build -f ./faas-currenttime.yml
  1. 镜像制作胜利时,控制台输入相似如下信息:
Step 27/30 : ENV fprocess="java -XX:+UseContainerSupport com.openfaas.entrypoint.App"
---> Running in 0f50636cc747
Removing intermediate container 0f50636cc747
---> 54a5c9a193c8
Step 28/30 : EXPOSE 8080
---> Running in 3252f165af15
Removing intermediate container 3252f165af15
---> c05afc826ec5
Step 29/30 : HEALTHCHECK --interval=5s CMD [-e /tmp/.lock] || exit 1
---> Running in 4106410be0a2
Removing intermediate container 4106410be0a2
---> 6d95b73b5f33
Step 30/30 : CMD ["fwatchdog"]
---> Running in 1606dbcd7003
Removing intermediate container 1606dbcd7003
---> 99a519ab82fd
Successfully built 99a519ab82fd
Successfully tagged bolingcavalry/faas-currenttime:latest
Image: bolingcavalry/faas-currenttime:latest built.
[0] < Building faas-currenttime done in 34.94s.
[0] Worker done.


Total build time: 34.94s
  1. 将镜像推送到镜像仓库,以便 Kubernetes 能够下载到此镜像,我这里用的是 hub.docker.com,因为我的 ID 是 <font color=”blue”>bolingcavalry</font>,所执行以下命令即可推送胜利:
docker push bolingcavalry/faas-currenttime:latest
  1. 执行以下命令部署函数到 OpenFaaS:
faas-cli deploy -f faas-currenttime.yml
  1. 控制台响应如下,可见部署曾经开始,并且给出了 endpoint:
[root@node1 20]# faas-cli deploy -f faas-currenttime.yml
Deploying: faas-currenttime.
WARNING! Communication is not secure, please consider using HTTPS. Letsencrypt.org offers free SSL/TLS certificates.

Deployed. 202 Accepted.
URL: http://192.168.133.187:31112/function/faas-currenttime.openfaas-fn
  1. 关上 web 端,在页面上可见新增的函数,验证操作如下图所示,可见入参的 JSON 内容能够被失常解析:

  1. 也能够在控制台用 curl 命令测试:
[root@node1 20]# curl \
> -H "Content-Type: application/json" \
> -X POST \
> --data '{"name":"Jerry}' \
> http://192.168.133.187:31112/function/faas-currenttime
{"success":true,"message":"Hello anonymous, response from [10.233.90.79], PID [11], 2020-11-20 02:14:46"}
  1. 执行命令 <font color=”blue”>faas-cli deploy -f faas-currenttime.yml</font> 开始部署,控制台曾经承受了部署申请,并给出了函数的 endpoint:
[root@node1 20]# faas-cli deploy -f faas-currenttime.yml
Deploying: faas-currenttime.
WARNING! Communication is not secure, please consider using HTTPS. Letsencrypt.org offers free SSL/TLS certificates.

Deployed. 202 Accepted.
URL: http://192.168.133.187:31112/function/faas-currenttime.openfaas-fn

清理

  • 删除函数的命令如下,仍旧是 <font color=”blue”>faas-currenttime.yml</font> 所在目录:
faas-cli remove -f faas-currenttime.yml
  • 至此,最根本的 Java 函数的开发、部署、验证都曾经实现,如果您也打算用 Java 开发 OpenFaaS 函数,心愿本文能给您一些参考;

你不孤独,欣宸原创一路相伴

  1. Java 系列
  2. Spring 系列
  3. Docker 系列
  4. kubernetes 系列
  5. 数据库 + 中间件系列
  6. DevOps 系列

欢送关注公众号:程序员欣宸

微信搜寻「程序员欣宸」,我是欣宸,期待与您一起畅游 Java 世界 …
https://github.com/zq2599/blog_demos

正文完
 0