欢迎访问我的GitHubhttps://github.com/zq2599/blog_demos
内容:所有原创文章分类汇总及配套源码,涉及Java、Docker、Kubernetes、DevOPS等;
OpenFaaS实战系列文章链接
- 部署
- 函数入门
- Java函数
- 模板操作(template)
- 大话watchdog
- of-watchdog(为性能而生)
- java11模板解析
- OpenFaaS实战之八:自制模板(maven+jdk8)
- OpenFaaS实战之九:终篇,自制模板(springboot+maven+jdk8)
- 本文是《OpenFaaS实战》系列的第八篇,经过前面的理论分析和实战练习,咱们对OpenFaaS了解得差不多了,也该搞事情了;
- 作为一个Java程序员,经常用到jdk8、maven、springboot这些东西,自然要关注官方模板是否支持,如下图,官方文档显示对java程序员的支持力度不够:不支持java8、用的是Gradle而非maven、不支持springboot,仅用vertx框架来支持web服务:

文章插图
- 既然官方模板不支持,咱们就自制模板来支持吧,本着先易后难的原则,本篇先做一个简单的模板:将官方的java11模板保持功能不变,jdk版本改造成java8,并将Gradle改成maven;
- 不可否认jdk8和maven都已一大把年纪了,新版jdk和Gradle都是更好的选择,不过本篇的重点是如何自定义模板,所以还请您给予包容...
- 今天要做的事情,如下图所示,咱们先做左边蓝色部分,编写模板代码,上传到github模板仓库,再做右侧绿色部分,像前面文章中使用官方模板那样去使用这个模板:

文章插图
- 接下来的实战由以下内容组成:
- 创建java项目,作为模板的基础源码
- 开发Dockerfile
- 完成模板配置并上传
- 验证模板
- 制作模板时最重要的就是提供完整的模板代码,接下来就来制作吧;
- 我这边用的是IDEA,建一个空maven项目,名为java8maven,用的是JDK8:
- 如下图,注意Language level要选择8:

文章插图
- pom.xml的内容如下,要注意的几个点稍后会说明:
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.bolingcavalry</groupId><artifactId>java8maven</artifactId><version>1.0-SNAPSHOT</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.apache.commons</groupId><artifactId>commons-math3</artifactId><version>3.6.1</version></dependency><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>23.0</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>com.openfaas</groupId><artifactId>model</artifactId><version>0.1.1</version></dependency><dependency><groupId>com.openfaas</groupId><artifactId>entrypoint</artifactId><version>0.1.0</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.11.0</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.10</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.1</version><configuration><source>1.8</source><target>1.8</target><encoding>UTF-8</encoding></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-dependency-plugin</artifactId><version>2.10</version><executions><execution><id>copy-dependencies</id><phase>package</phase><goals><goal>copy-dependencies</goal></goals><configuration><outputDirectory>${project.build.directory}/lib</outputDirectory><overWriteReleases>false</overWriteReleases><overWriteSnapshots>false</overWriteSnapshots><overWriteIfNewer>true</overWriteIfNewer></configuration></execution></executions></plugin><plugin><artifactId>maven-assembly-plugin</artifactId><version>3.0.0</version><configuration><archive><manifest><mainClass>com.openfaas.entrypoint.App</mainClass></manifest><manifestEntries><Class-Path>.</Class-Path></manifestEntries></archive><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin></plugins></build></project>- 上述pom.xml的内容中,有几处需要注意:
- openfaas的model和entrypoint这两个jar是整个服务可运行的基础;
- 有些常用的jar依赖也被加入了,您可以酌情自行增删;
- 插件maven-compiler-plugin用来指定编译时的JDK版本;
- 插件maven-dependency-plugin和maven-assembly-plugin用来将整个java代码和依赖库打包到一个jar文件中,这样制作Docker镜像会方便很多;
- 新建一个java类:com.openfaas.function.Handler,源码和《OpenFaaS实战之三:Java函数》中的Handler.java一模一样,如下:
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;}}- pom.xml所在目录下,新建文件夹m2,里面增加maven的配置文件settings.xml,该文件是在FaaS开发过程中,制作镜像时用到的(制作镜像时会编译构建java项目),强烈建议在里面配置好您的maven私服,或者阿里云镜像,这样制作镜像时会快很多,我这里已经配置了阿里云镜像,依然耗时四分多钟(如下图),所以如果您有nexus3私服一定要优先考虑:

文章插图
- 至此,编码工作已完成,可见这就是个普通maven工程,来试试能不能正常运行;
- 执行命令mvn clean package -U -DskipTests,成功后会在target目录生成文件java8maven-1.0-SNAPSHOT-jar-with-dependencies.jar;
- 运行上述jar文件,命令是java -jar java8maven-1.0-SNAPSHOT-jar-with-dependencies.jar;
- 上述jar运行起来后会监听8082端口的POST请求,我这里用postman来试试,如下图,可以收到后台返回的最新数据:

文章插图
- 后台控制台也会打印出预期的内容:

文章插图
- 代码写完了,接下来要考虑的如何制作Docker镜像,即Dockerfile的编写;
- 前面的实战中咱们已经体验过,开发FaaS的时候会将代码编译构建制作成镜像,因此对应的Dockerfile也要准备好,下面是完整的Dockerfile内容,已经添加详细的注释,就不再赘述了:
# 用maven镜像作为基础镜像,用于编译构建java项目FROM maven:3.6.3-openjdk-8 as builderWORKDIR /home/app# 将整个项目都复制到/home/app目录下COPY . /home/app/# 进入pom.xml所在目录执行构建命令,指定m2/settings.xml文件作为配置文件,# 请在settings.xml中配置好私服,否则构建速度极慢RUN cd function && mvn clean package -U -DskipTests --settings ./m2/settings.xml # of-watchdog里面有二进制文件watchdog,制作镜像时要用到FROM openfaas/of-watchdog:0.7.6 as watchdog# openjdk镜像是容器的运行环境FROM openjdk:8-jre-slim as ship# 为了安全起见,在生产环境运行容器时不要用指root帐号和群组RUN addgroup --system app \&& adduser --system --ingroup app app# 从of-watchdog镜像中复制二进制文件fwatchdog,这是容器的启动进程COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog# 赋予可执行权限RUN chmod +x /usr/bin/fwatchdogWORKDIR /home/app# 前面用maven编译构建完毕后,这里将构建结果复制到镜像中COPY --from=builder /home/app/function/target/java8maven-1.0-SNAPSHOT-jar-with-dependencies.jar ./java8maven-1.0-SNAPSHOT-jar-with-dependencies.jar# 指定容器的运行帐号user app# 指定容器的工作目录WORKDIR /home/app/# fwatchdog收到web请求后的转发地址,java进程监听的就是这个端口ENV upstream_url="http://127.0.0.1:8082"# 运行模式是httpENV mode="http"# 拉起业务进程的命令,这里就是启动java进程ENV fprocess="java -jar java8maven-1.0-SNAPSHOT-jar-with-dependencies.jar"# 容器对外暴露的端口,也就是fwatchdog进程监听的端口EXPOSE 8080# 健康检查HEALTHCHECK --interval=5s CMD [ -e /tmp/.lock ] || exit 1# 容器启动命令,这里是执行二进制文件fwatchdogCMD ["fwatchdog"]模板配置- 现在材料已经准备完毕了,再整理一下准备提交到github上,就可以作为OpenFaaS模板使用了;
- 新建一个文件夹,名为simplejava8;
- simplejava8目录下新建文件template.yml,内容如下:
language: simplejava8welcome_message: |You have created a function using the java8 and maven template- 将前面的Dockerfile文件复制到simplejava8目录下;
- 前面咱们创建的maven工程,最外层的文件夹名为java8maven,请将此文件夹改名为function,然后将整个文件夹都复制到simplejava8目录下;
- 此刻的simplejava8目录下应该是这些内容:
[root@hedy 002]# tree simplejava8simplejava8├── Dockerfile├── function│├── java8maven.iml│├── m2││└── settings.xml│├── pom.xml│└── src│├── main││├── java│││└── com│││└── openfaas│││└── function│││└── Handler.java││└── resources│└── test│└── java└── template.yml11 directories, 6 files- 将这些内容全部上传到github上,我这里路径是https://github.com/zq2599/openfaas-templates/tree/master/template,这里面已经有三个模板了,本次新增的如下图红框:

文章插图
- 至此,模板制作完成,接下来验证此模板是否可用;
- 接下来要做的,就是下图右侧的绿色部分:

文章插图
- 登录一台配好OpenFaaS客户端的电脑,找个干净目录执行以下命令,将github上所有模板下载下来:
faas template pull https://github.com/zq2599/openfaas-templates- 控制台响应如下,提示下载了三个模板,符合预期:
[root@hedy 07]# faas template pull https://github.com/zq2599/openfaas-templatesFetch templates from repository: https://github.com/zq2599/openfaas-templates at 2021/03/07 08:44:29 Attempting to expand templates from https://github.com/zq2599/openfaas-templates2021/03/07 08:44:32 Fetched 3 template(s) : [dockerfile java11extend simplejava8] from https://github.com/zq2599/openfaas-templates- 用faas new --list查看列表如下:
[root@hedy 07]# faas new --listLanguages available as templates:- dockerfile- java11extend- simplejava8- 看看template/simplejava8目录下的内容,和前面上传的一模一样:
[root@hedy 07]# tree template/simplejava8/template/simplejava8/├── Dockerfile├── function│├── java8maven.iml│├── m2││└── settings.xml│├── pom.xml│└── src│└── main│└── java│└── com│└── openfaas│└── function│└── Handler.java└── template.yml8 directories, 6 files- 有了模板就可以创建函数了,执行以下命令创建名为faas-simplejava8demo的函数:
faas-cli new faas-simplejava8demo --lang simplejava8 -p bolingcavalry- 控制台提示如下,此时当前目录下新增文件夹faas-simplejava8demo,这就是新建函数的代码目录:
[root@hedy 07]# faas-cli new faas-simplejava8demo --lang simplejava8 -p bolingcavalryFolder: faas-simplejava8demo created.____________ / _ \ _ _____ _ __ |___|_ ___ _/ ___|| | | | '_ \ / _ \ '_ \| |_ / _` |/ _` \___ \| |_| | |_) |__/ | | |_| (_| | (_| |___) | \___/| .__/ \___|_| |_|_|\__,_|\__,_|____/|_|Function created in folder: faas-simplejava8demoStack file written: faas-simplejava8demo.ymlNotes:You have created a function using the java8 and maven template[root@hedy 07]# lsfaas-simplejava8demofaas-simplejava8demo.ymltemplate- 文件夹faas-simplejava8demo的内容如下,现在妥了,用IDEA等IDE工具以maven工程形式导入,然后根据业务需求修改这个工程即可:
[root@hedy 07]# tree faas-simplejava8demofaas-simplejava8demo├── java8maven.iml├── m2│└── settings.xml├── pom.xml└── src└── main└── java└── com└── openfaas└── function└── Handler.java7 directories, 4 files- 现在可以开发业务了,这里为了测试,新增了一行代码,如下图红框:

文章插图
- 开始编译构建吧,执行以下命令:
faas-cli build -f ./faas-simplejava8demo.yml- 构建完成后将镜像推送到镜像仓库,以便Kubernetes可以下载到此镜像,我这里用的是hub.docker.com,因为我的ID是bolingcavalry,所执行以下命令即可推送成功(要先执行docker login命令登录):
docker push bolingcavalry/faas-simplejava8demo:latest- 执行以下命令部署函数到OpenFaaS:
faas-cli deploy -f faas-simplejava8demo.yml- 控制台响应如下,可见部署已经开始,并且给出了endpoint:
[root@hedy 07]# faas-cli deploy -f faas-simplejava8demo.ymlDeploying: faas-simplejava8demo.WARNING! You are not using an encrypted connection to the gateway, consider using HTTPS.Deployed. 202 Accepted.URL: http://192.168.50.75:31112/function/faas-simplejava8demo.openfaas-fn- 打开web端,在页面上可见新增的函数,验证操作如下图所示,可见入参的JSON内容可以被正常解析:

文章插图
- 也可以在控制台用curl命令测试:
[root@hedy 07]# curl \> -H "Content-Type: application/json" \> -X POST \> --data '{"name":"Jerry}' \> http://192.168.50.75:31112/function/faas-simplejava8demo{"success":true,"foo":"bar","message":"Hello anonymous, response from [10.244.0.168], PID [14], 2021-03-07 03:32:15"}清理- 删除函数的命令如下,依旧是faas-simplejava8demo.yml所在目录:
faas-cli remove -f faas-simplejava8demo.yml- 至此,自制的maven+jdk8的模板,从开发到验证咱们已经全部走了一遍,相信您对OpenFaaS的理解也已经更加全面和深入了,本篇是为开发模板练手用的,实用价值不大,接下来的文章咱们要做个实用的模板:jdk8+maven+springboot
- Java系列
- Spring系列
- Docker系列
- kubernetes系列
- 数据库+中间件系列
- DevOps系列
https://github.com/zq2599/blog_demos
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
