欢迎访问我的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)

本篇概览

  • 本文是《OpenFaaS实战》系列的第七篇,经过前面的知识储备,咱们对OpenFaaS的服务调用和容器运行原理已经了然于胸,可以更深入的研究和使用了OpenFaaS了;
  • 想要更加自由的开发函数,加入更多符合业务需要的特性,显然官方提供的几个模板是无法满足咱们的需要,以欣宸熟悉的Java为例,现有的java11和java11-vert-x存在以下问题:
  1. 是基于Gradle的,而实际上习惯使用Maven的开发者并不少;
  2. 没有Spring、SpringBoot;
  3. 不支持类似dubbo、SpringCloud等分布式调用;
  • 综上所述,java程序员常用的技术栈很难在OpenFaaS的官方模板得到支持,没关系,咱们可以自己开发模板支持上述能力,不过这不是本章的任务,本章的目标是一起深入了解java11模板,摸清官方套路,为后面的自定义模板开发做好充分的准备,本篇文章有以下内容:
  1. 解析Dockerfile
  2. Java源码学习
  • 没错,java11模板很简单,很快就能了解其中原理;

解析Dockerfile

  • 回顾of-watchdog的http模式内部架构,如下图:

  • 从上图可见函数功能代码能被调用的关键有以下两点:
  1. 有微服务(child)在监听指定端口;
  2. of-watchdog(parent)收到外部请求会转发到微服务监听的端口;
  • 最为关键的微服务和of-watchdog都聚集在同一个docker容器中,因此该docker镜像的Dockerfile文件就是一切的关键,接下来一起看看这个文件;
  • 在OpenFaaS环境执行命令faas template pull可以拉取全部官方模板,在template/java11目录下是该模板的全部文件:
  1. [root@node1 template]# tree java11
  2. java11
  3. ├── build.gradle
  4. ├── Dockerfile
  5. ├── function
  6. ├── build.gradle
  7. ├── gradle
  8. └── wrapper
  9. ├── gradle-wrapper.jar
  10. └── gradle-wrapper.properties
  11. ├── gradlew
  12. ├── gradlew.bat
  13. ├── settings.gradle
  14. └── src
  15. ├── main
  16. └── java
  17. └── com
  18. └── openfaas
  19. └── function
  20. └── Handler.java
  21. └── test
  22. └── java
  23. └── HandlerTest.java
  24. ├── gradle
  25. └── wrapper
  26. ├── gradle-wrapper.jar
  27. └── gradle-wrapper.properties
  28. ├── README.md
  29. ├── settings.gradle
  30. └── template.yml
  • 打开Dockerfile阅读,我在脚本的关键位置添加了注释辅助理解,如下所示:
  1. # 使用multi-stage builds特性,将整个镜像构建分为多个阶段
  2. # 名为builder的镜像里面会生成java代码编译构建出来的结果
  3. FROM openjdk:11-jdk-slim as builder
  4. ENV GRADLE_VER=6.1.1
  5. # 应用更新,并且安装后面要用到的应用
  6. RUN apt-get update -qqy \
  7. && apt-get install -qqy \
  8. --no-install-recommends \
  9. curl \
  10. ca-certificates \
  11. unzip
  12. # 下载指定版本的gradle,并解压,再删除压缩包(避免镜像体积变大)
  13. RUN mkdir -p /opt/ && cd /opt/ \
  14. && echo "Downloading gradle.." \
  15. && curl -sSfL "https://services.gradle.org/distributions/gradle-${GRADLE_VER}-bin.zip" -o gradle-$GRADLE_VER-bin.zip \
  16. && unzip gradle-$GRADLE_VER-bin.zip -d /opt/ \
  17. && rm gradle-$GRADLE_VER-bin.zip
  18. # Export some environment variables
  19. ENV GRADLE_HOME=/opt/gradle-$GRADLE_VER/
  20. ENV PATH=$PATH:$GRADLE_HOME/bin
  21. RUN mkdir -p /home/app/libs
  22. ENV GRADLE_OPTS="-Dorg.gradle.daemon=false"
  23. WORKDIR /home/app
  24. # 把编译构建涉及的所有内容都复制到镜像的/home/app/目录,
  25. # 包括配置文件、java源码等
  26. COPY . /home/app/
  27. # 开始编译构建
  28. RUN gradle build
  29. # 打印文件列表
  30. RUN find .
  31. # 名为watchdog的镜像,注意基础镜像是openfaas/of-watchdog
  32. FROM openfaas/of-watchdog:0.7.6 as watchdog
  33. # 这个ship才是最终的镜像,前面的builder和watchdog都是为ship准备内容的
  34. # 为了控制体积,ship里面是jre,而非jdk
  35. FROM openjdk:11-jre-slim as ship
  36. RUN apt-get update -qqy \
  37. && apt-get install -qqy \
  38. --no-install-recommends \
  39. unzip
  40. # 为了安全起见不使用root帐号,这里增加名为app的群组和用户
  41. RUN addgroup --system app \
  42. && adduser --system --ingroup app app
  43. # 从watchdog镜像获取可执行文件fwatchdog
  44. COPY --from=watchdog /fwatchdog /usr/bin/fwatchdog
  45. # 增加可执行权限
  46. RUN chmod +x /usr/bin/fwatchdog
  47. # 设置执行命令的目录
  48. WORKDIR /home/app
  49. # 从builder获取整个gradle项目的构建结果
  50. COPY --from=builder /home/app/function/build/distributions/function-1.0.zip ./function-1.0.zip
  51. # 执行运行容器进程的帐号是app
  52. user app
  53. # 解压构建结果
  54. RUN unzip ./function-1.0.zip
  55. WORKDIR /home/app/
  56. # of-watchdog转发的地址,也就是微服务监听的地址
  57. ENV upstream_url="http://127.0.0.1:8082"
  58. # of-watchdog的模式
  59. ENV mode="http"
  60. # 微服务是java应用,要用到这个classpath
  61. ENV CLASSPATH="/home/app/function-1.0/function-1.0.jar:/home/app/function-1.0/lib/*"
  62. # 启动微服务的命令
  63. ENV fprocess="java -XX:+UseContainerSupport com.openfaas.entrypoint.App"
  64. # 对外暴露的端口,of-watchdog监听的
  65. EXPOSE 8080
  66. # 监控检查
  67. HEALTHCHECK --interval=5s CMD [ -e /tmp/.lock ] || exit 1
  68. # 容器启动时执行的命令,既启动of-watchdog
  69. CMD ["fwatchdog"]

  • 为了更清晰的看到脚本中三个任务是如何协同的,将整个Dockerfile的脚本用下图表示,可见最终的镜像来自ship,左侧的builder和watchdog都是为ship提供内容的:

java工程分析

  1. 从Dockerfile中得知微服务的启动命令如下:
  1. java -XX:+UseContainerSupport com.openfaas.entrypoint.App
  1. 只要搞清楚上述命令对应的实现,整个java11模板就全部掌握了,接下来就来研究这个com.openfaas.entrypoint.App类;
  2. 打开文件template/java11/function/build.gradle,看到依赖关系如下图,红框中的库应该就是com.openfaas.entrypoint.App的来源了:

  1. 上图红框中的库,代码已经开源,地址是:https://github.com/openfaas/templates-sdk/tree/master/java11
  2. 打开App.java文件后,一切谜底都被揭开了,这个java11模板的源码还真是简单呀,先看入口的main方法:
  1. public static void main(String[] args) throws Exception {
  2. // 监听8082端口,和Dockerfile中of-watchdog转发请求的端口保持一致
  3. int port = 8082;
  4. // handler是真正处理请求的实例
  5. HandlerProvider p = HandlerProvider.getInstance();
  6. IHandler handler = p.getHandler();
  7. // 配置监听对象,并将handler绑定过来
  8. HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
  9. InvokeHandler invokeHandler = new InvokeHandler(handler);
  10. // 设置path,开始监听
  11. server.createContext("/", invokeHandler);
  12. server.setExecutor(null); // creates a default executor
  13. server.start();
  14. }
  1. 有没有觉得上述代码和sockek编程很像;
  2. App.java中还有静态类InvokeHandler的定义,这个类的主要功能就是接收web请求的数据,加工成IRequest实例,丢给IHandler实例去处理,处理完成后包装http响应,核心代码片段如下:
  1. // 把request内容封装到IRequest实例中
  2. IRequest req = new Request(requestBody, reqHeadersMap,t.getRequestURI().getRawQuery(), t.getRequestURI().getPath());
  3. // 执行业务逻辑处理请求
  4. IResponse res = this.handler.Handle(req);
  5. // 得到处理后的结果
  6. String response = res.getBody();
  7. ...
  1. 上述代码可见业务逻辑的执行的关键是this.handler.Handle(req),而真正执行业务的代码是咱们自己写的Handler.java,要搞清楚它们之间的关系,就要看HandlerProvider.java,如下图,一些都清楚了,咱们开发函数时,编写的业务功能都在Handler.java中,而Handler是AbstractHandler的实现类,于是下图红框1中就会找到Handler,红框2可以返回Handler实例,在InvokeHandler执行this.handler.Handle(req)时,就是Handler实例在处理web请求了:

  1. 至此,java代码的分析就完成了,这个微服务其实很简单,就像咱们做Socket编程练习那样,自己编码监听端口并编写处理逻辑;

小结

最后做个小结,将前面展开的思路收敛起来,如下图:

看到这里,对于java11模板的内部实现及其执行原理,相信在您眼里应该没有什么秘密了,为了制作更好用的java模板,咱们已经做了充分准备,接下来的文章,请随欣宸一起实战自定义java模板;

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

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

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

微信搜索「程序员欣宸」,我是欣宸,期待与您一同畅游Java世界...

https://github.com/zq2599/blog_demos

OpenFaaS实战之七:java11模板解析的更多相关文章

  1. OpenFaaS实战之四:模板操作(template)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  2. OpenFaaS实战之八:自制模板(maven+jdk8)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  3. OpenFaaS实战之九:终篇,自制模板(springboot+maven+jdk8)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  4. OpenFaaS实战之一:部署

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  5. OpenFaaS实战之二:函数入门

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  6. OpenFaaS实战之三:Java函数

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  7. OpenFaaS实战之五:大话watchdog

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  8. OpenFaaS实战之六:of-watchdog(为性能而生)

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  9. [原创].NET 业务框架开发实战之七 业务层初步构想

    原文:[原创].NET 业务框架开发实战之七 业务层初步构想 .NET 业务框架开发实战之七 业务层初步构想 前言:本篇主要讲述如何把DAL和BLL衔接起来. 本篇议题如下: 1.       DAL ...

随机推荐

  1. B站英文教学视频的字幕获取 学习必看!

    前言 最近在B站看一些纯英文的课程,视频课程有的是纯中文字幕的,有的是纯英文字幕的.由于英文的重要性,一份字幕的文档在我们观看后,留着日后粗略再读是很有益处的.但是为了得到这个英文字幕走了许多弯路.最 ...

  2. 基于ABP落地领域驱动设计-04.领域服务和应用服务的最佳实践和原则

    目录 系列文章 领域服务 应用服务 学习帮助 系列文章 基于ABP落地领域驱动设计-00.目录和前言 基于ABP落地领域驱动设计-01.全景图 基于ABP落地领域驱动设计-02.聚合和聚合根的最佳实践 ...

  3. 动态路由及RIP协议

    动态路由及 RIP协议 目录 一.动态路由协议 1.1.定义 1.2.特点 1.3.动态路由协议概述 1.4.度量值 1.5.收敛 1.6.静态路由和动态路由的比较 二.动态路由协议的分类 2.1.距 ...

  4. Golang修改操作系统时间

    Golang修改操作系统时间 需求 程序有时需要和服务器对时,发现延迟过高修改本地时间,这段代码网上抄的,实测可用,windows环境需要以管理员身份启动命令提示符调试 实现Demo package ...

  5. Maven项目无法下载JAR包,输入mvn help:system出现No plugin found for prefix 'help' in the current project and in the plugin groups的解决方案

    这个问题困扰了我很久,一直无法解决:我在虚拟机里面按照同样的步骤配置了三次maven项目,每次都能成功:可一旦到外面maven项目总是创建失败,输入mvn help:system总是出现No plug ...

  6. 工作3年,还不会写单元测试?新技能get!

    历史遗留代码不敢重构? 每次改代码都要回归所有逻辑? 提测被打回? 在近期的代码重构的过程中,遇到了各式各样的问题.比如调整代码顺序导致bug,取反操作逻辑丢失,参数校验逻辑被误改等. 上线前需要花大 ...

  7. Spring源码编译一次性通过&遇到的坑解决方法

    前言 spring源码本地编译,按网上的博客参考资料的操作步骤,总是会出现各种莫名其妙的错误.根据错误信息找解决方案,但在自己的环境下又总是编译不过去.结合参加培训学习Jack老师提供的方法,自己多种 ...

  8. nginx开启tls1.2及一些注意问题

    因为http传输是明文,通过抓包很容易获取到报文, 所以现在很多站点都开启了https,HTTPS在HTTP的基础上加入了SSL协议,对传输的数据进行加密. 目前主流的ssl协议是tlsv1.2 ng ...

  9. 《PHP扩展学习系列》系列分享专栏

    <PHP扩展学习系列>系列分享专栏   <PHP扩展学习系列>已整理成PDF文档,点击可直接下载至本地查阅https://www.webfalse.com/read/20177 ...

  10. [Vue入门及介绍,基础使用、MVVM架构、插值表达式、文本指令、事件指令]

    [Vue入门及介绍,基础使用.MVVM架构.插值表达式.文本指令.事件指令] 1)定义:javascript渐进式框架 ​ 渐进式:可以控制一个页面的一个标签,也可以控制一系列标签,也可以控制整个页面 ...