4.启动脚本改造
Otter包括两个部分,管理控制台manager和工作运行节点node,正常情况下都是用各自的启动脚本startup.sh启动的。
为了适配k8s,我们需要对启动脚本做改造,本文以otter-manager的启动脚本为例,otter-node也是类似。
将启动脚本startup.sh改造为 startup-moon.sh,重点解决两个问题
- 前台进程保持运行
- jvm参数自定义改造
4.1 前台进程保持运行
由于容器中用entrypoint启动的进程为1号进程,一旦1号进程执行结束,容器就会退出了。
而原本的startup.sh中,用java启动后,使用 “&” 将java进程转换为后台进程,所以startup.sh作为1号进程会很快执行结束,容器就会自动退出了。
所以我们需要将1号进程保持住,不要退出。
这里考虑了两个方案:
- Startup.sh脚本中增加一个前台进程进行保持,比如 tail -f /dev/null 命令
- 将“&”去掉,让java启动后就作为前台进程一直保持
后来考虑了一下,还是选择了方案二。主要原因是为了利用pod自动重启的特性。
如果Java进程意外退出了,那么方案二就能使得1号进程也结束,然后pod就能自动重启了。而方案一的话,由于startup.sh脚本仍然在执行tail,所以即使java进程退出,1号进程也不会结束。
具体修改如下:
最终pod中的进程如图所示
- 1号进程是启动脚本
- 1号进程的子进程是otter的java应用进程(前台进程)
4.2 虚拟机大小自定义配置
由于otter项目中,将jvm的启动参数配置在了start.sh中,不方便进行手动配置。
因此,将start.sh的配置jvm参数的逻辑注释掉,采用自己配置的环境变量JAVA_OPTIONS进行注入。
这个环境变量的注入方式也比较简单,就是在Deployment中的env配置的(蓝色框部分),方便以后手动修改jvm参数大小而不用修改镜像。
5.k8s上固定IP/Port访问
otter-node的部署中,有个比较特殊的地方。
不同于普通的微服务的无状态扩展,otter-node的部署必须指定nid、ip、port,这种设计据说是为解决单机部署多实例而设计的,允许单机多node指定不同的端口(具体可以参考官方wiki,https://github.com/alibaba/otter/wiki/Node_Quickstart,这里不展开说明)。
还是直接看看如何在k8s上进行适配吧。
这里采用了k8s的NodePort进行处理。
NodePort 服务是引导外部流量到你的服务的最原始方式。NodePort,正如这个名字所示,在所有节点(虚拟机)上开放一个特定端口,任何发送到该端口的流量都被转发到对应服务。如下图所示。
在上面的配置中,可以使用IP1:3000 或者 IP2:3000 或者 IP3:3000 访问service。
当然,为了保证不绑定特定KVM的IP,我们在前面挂一个SLB服务,通过访问SLB的 虚拟IP:PORT 的形式访问。
对于otter部署来说,otter-manager需要两组 IP:PORT、每个node需要三组 IP:PORT。
注意,由于otter部署中,每个node需要暴露的port都是不同的,所以每次新增一个otter-node,都需要新增三组 IP:PORT。
我们以otter-node为例,来看下NodePort类型的Service的yml文件吧。
- kind为service
- type为NodePort
- 配置了三组端口。port/targetport都是应用暴露端口,而nodePort是对外访问端口。
6.总结
经过这样的改造,我们就能用k8s的部署otter-manager和otter-node了,并且能够快速扩容节点、弹性使用机器资源。
我们回顾一下其中的关键问题和技巧:
- Dockerfile编写中,可以把环境相关依赖打成一个新的基础镜像,提高后续应用镜像的构建速度。
- Dockerfile中,可以通过ARG定义一些构建过程中的变量,进行替换。
- 对于不同环境的配置文件,可以在不同环境(k8s的namespace)下配置不同的ConfigMap,然后在Deployment文件中通过volumeMounts的方式挂载进去。
- 对于后台进程,需要改造为前台进程使得pod能够保持
- 对于一些特定的环境变量,可以在Deployment中通过env进行传入。
其他开源项目如果有需要上k8s的,这些技巧应该都能用上。