Resolve Dependency Issue for a Simple Java Program
最近需要把一个服务从对 Envoy 的依赖迁移到 Nginx。我们大都是 GRPC 请求,所以需要代码对 http2 + ssl 做支持。
GRPC 是基于 h2 的,当使用 Envoy 的时候,代码都是发 h2c 的情况给本地的 envoy。这个过程没有 ssl 握手。而 Nginx 不支持 h2c 的支持,必须处理 ssl 握手。我们的服务都是在 Nginx 后面的,Nginx 层面也做了会多 Virtual Host 的配置,所以需要通过 Host 来做匹配,这个 Host 也必须得正确,要不然就是会匹配到 default 的 server,无非是得到一个 404。
我们并没有对每个 Virtual Host 都配置 FQDN,我们只对 Nginx 整体配置了一个 FQDN,这里假设为 lb.abc.com。后面的服务的 Host 假设为 svc1。那连接的时候实际上 ssl 握手是和域名 lb.abc.com,http 协议的 Host 匹配使用的是 svc1。这是两个层面的事情需要分开理解。具体可以看我这篇 https://wdicc.com/https-sni-host-and-envoy/ ,这个不是本篇重点。
重点是,我需要找到一个方法绕开这个问题。最简单的调试方法当然就是本地写一个小程序来调试。对于 python 程序,我们可以使用 virtualenv 来创建一个虚拟环境然后通过 pip 来解决依赖问题。那么 java 怎么办? io.grpc
这个库不在标准库里面。搜了一下好像使用 maven 是比较简单的一个方式,再说几年前也使用过 maven 也不那么陌生。
maven 项目也有个结构要求,况且那个 pom.xml 没可能自己手写。所以自然就找到了这个文档 Maven in 5 Minutes。里面提供了初始化项目的命令。
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.5 -DinteractiveMode=false
然后把自己的依赖写到那个 pox.xml 里面。依赖的写法一般是去搜包的时候找到 maven repo 然后里面会直接给你一段配置,复制就可以。有了这些之后就可以写代码了。正常的做法好像是使用 mvn package
打一个包,然后使用 java -cp target/xx.jar
命令来测试。我为了简单直接写到了 test 目录里面,这样使用 mvn test
命令就可以测试了,虽然会有一堆的其他内容,但是好歹一个命令就能搞定。我中间还遇到过一个问题,使用 vscode 编辑过代码之后,不知道哪里 cache 了旧代码,运行命令的时候会发现自己的改动没有生效。后来使用 mvn clean install
解决的。
按说故事到这里就结束了,但是感觉 grpc 这块的一些东西也应该可以写写,所以就一起记录了一下。
因为我需要测试 grpc 请求,所以还必须得写 .proto 文件和编译这些文件,这些 proto 必须还得是 sv1 服务支持的。折腾这些就麻烦了。还好 grpc 有一个 healthcheck 的约定协议 ,一般 server 都会支持这个。所以可以利用这个来测试通讯。
而支持这个协议的代码在 io.grpc
包里面已经有了,直接使用 io.grpc.health.v1
下的一系列方法就行。这样一套下来就可以测试了。我中间为了编译 proto 文件还走了一点弯路,使用 protoc 命令可以把 proto 文件编译成不同的语言,但是对于 java,还需要有一个 protoc-gen-grpc-java 这个东西的支持。我看据说可以在 maven 里面配置之后会给我们自动处理这个,但是我配置了好像没什么用,还得自己编译。不过如果只是 healthcheck 协议的话,用 io.grpc.health.v1
最简单了。
我使用了 InsecureTrustManagerFactory.INSTANCE.getTrustManagers()
这个 TrustManager 来绕开的 SNI 检查。我尝试过自己定义一个 TrustManager 来绕开,不过失败了,对 Java 还是不熟悉,另外感觉我们内网服务也没必要折腾太久,毕竟写这代码也不是我主业,所以就放弃后续研究了。我感觉自己实现一个 TrustManager 然后在 checkServerTrusted
方法里面实现自己的证书验证方法应该是可行的。
以上就是瞎逼折腾,不过生命在于折腾不是么?