快捷搜索:  汽车  科技

idea中maven的常用操作(OpenFaaS实战之八自制模板)

idea中maven的常用操作(OpenFaaS实战之八自制模板)

欢迎访问我的GitHub

https://github.com/zq2599/blog_demos

内容:所有原创的分类和汇总,及配套源码,涉及Java、Docker、Kubernetes、DevOPS等

本篇概览
  • 本文是《OpenFaaS实战》系列的第八篇,经过前面的理论分析和实战练习,咱们对OpenFaaS了解得差不多了,也该搞事情了;
  • 作为一个Java程序员,经常用到jdk8、maven、springboot这些东西,自然要关注官方模板是否支持,如下图,官方文档显示对java程序员的支持力度不够:不支持java8、用的是Gradle而非maven、不支持springboot,仅用vertx框架来支持web服务:

idea中maven的常用操作(OpenFaaS实战之八自制模板)(1)

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

idea中maven的常用操作(OpenFaaS实战之八自制模板)(2)

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

idea中maven的常用操作(OpenFaaS实战之八自制模板)(3)

  • 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> 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121

  • 上述pom.xml的内容中,有几处需要注意:
  1. openfaas的model和entrypoint这两个jar是整个服务可运行的基础;
  2. 有些常用的jar依赖也被加入了,您可以酌情自行增删;
  3. 插件maven-compiler-plugin用来指定编译时的JDK版本;
  4. 插件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; } } 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126

  • pom.xml所在目录下新建文件夹m2,里面增加maven的配置文件settings.xml,该文件是在FaaS开发过程中,制作镜像时用到的(制作镜像时会编译构建java项目),强烈建议在里面配置好您的maven私服,或者阿里云镜像,这样制作镜像时会快很多,我这里已经配置了阿里云镜像,依然耗时四分多钟(如下图),所以如果您有nexus3私服一定要优先考虑:

idea中maven的常用操作(OpenFaaS实战之八自制模板)(4)

  • 至此,编码工作已完成,可见这就是个普通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来试试,如下图,可以收到后台返回的最新数据:

idea中maven的常用操作(OpenFaaS实战之八自制模板)(5)

  • 后台控制台也会打印出预期的内容:

idea中maven的常用操作(OpenFaaS实战之八自制模板)(6)

  • 代码写完了,接下来要考虑如何制作Docker镜像,即Dockerfile的编写;
开发Dockerfile
  • 前面的实战中咱们已经体验过,开发FaaS的时候会将代码编译构建制作成镜像,因此对应的Dockerfile也要准备好,下面是完整的Dockerfile内容,已经添加详细的注释,就不再赘述了:

# 用maven镜像作为基础镜像,用于编译构建java项目 FROM maven:3.6.3-openjdk-8 as builder WORKDIR /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/fwatchdog WORKDIR /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" # 运行模式是http ENV 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 # 容器启动命令,这里是执行二进制文件fwatchdog CMD ["fwatchdog"]模板配置

  • 现在材料已经准备完毕了,再整理一下准备提交到github上,就可以作为OpenFaaS模板使用了;
  • 新建一个文件夹,名为simplejava8;
  • simplejava8目录下新建文件template.yml,内容如下:

language: simplejava8 welcome_message: | You have created a function using the java8 and maven template

  • 将前面的Dockerfile文件复制到simplejava8目录下;
  • 前面咱们创建的maven工程,最外层的文件夹名为java8maven,请将此文件夹改名为function,然后将整个文件夹都复制到simplejava8目录下;
  • 此刻的simplejava8目录下应该是这些内容:

[root@hedy 002]# tree simplejava8 simplejava8 ├── Dockerfile ├── function │ ├── java8maven.iml │ ├── m2 │ │ └── settings.xml │ ├── pom.xml │ └── src │ ├── main │ │ ├── java │ │ │ └── com │ │ │ └── openfaas │ │ │ └── function │ │ │ └── Handler.java │ │ └── resources │ └── test │ └── java └── template.yml 11 directories 6 files

  • 将这些内容全部上传到github上,我这里路径是https://github.com/zq2599/openfaas-templates/tree/master/template,这里面已经有三个模板了,本次新增的如下图红框:

idea中maven的常用操作(OpenFaaS实战之八自制模板)(7)

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

idea中maven的常用操作(OpenFaaS实战之八自制模板)(8)

  • 登录一台配好OpenFaaS客户端的电脑,找个干净目录执行以下命令,将github上所有模板下载下来:

faas template pull https://github.com/zq2599/openfaas-templates

  • 控制台响应如下,提示下载了三个模板,符合预期:

[root@hedy 07]# faas template pull https://github.com/zq2599/openfaas-templates Fetch 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-templates 2021/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 --list Languages 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.yml 8 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 bolingcavalry Folder: faas-simplejava8demo created. ___ _____ ____ / _ \ _ __ ___ _ __ | ___|_ _ __ _/ ___| | | | | '_ \ / _ \ '_ \| |_ / _` |/ _` \___ \ | |_| | |_) | __/ | | | _| (_| | (_| |___) | \___/| .__/ \___|_| |_|_| \__ _|\__ _|____/ |_| Function created in folder: faas-simplejava8demo Stack file written: faas-simplejava8demo.yml Notes: You have created a function using the java8 and maven template [root@hedy 07]# ls faas-simplejava8demo faas-simplejava8demo.yml template 1234567891011121314151617

  • 文件夹faas-simplejava8demo的内容如下,现在妥了,用IDEA等IDE工具以maven工程形式导入,然后根据业务需求修改这个工程即可:

[root@hedy 07]# tree faas-simplejava8demo faas-simplejava8demo ├── java8maven.iml ├── m2 │ └── settings.xml ├── pom.xml └── src └── main └── java └── com └── openfaas └── function └── Handler.java 7 directories 4 files

  • 现在可以开发业务了,这里为了测试,新增了一行代码,如下图红框:

idea中maven的常用操作(OpenFaaS实战之八自制模板)(9)

  • 开始编译构建吧,执行以下命令:

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.yml Deploying: 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内容可以被正常解析:

idea中maven的常用操作(OpenFaaS实战之八自制模板)(10)

  • 也可以在控制台用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
欢迎关注我的公众号:程序员欣宸

idea中maven的常用操作(OpenFaaS实战之八自制模板)(11)

猜您喜欢: