1.背景
otter是阿里开源的分布式数据库同步系统,基于数据库增量日志解析,并准实时同步到本机房或异地机房的mysql/oracle数据库(相关内容可以参考https://github.com/alibaba/otter,本文不做过多赘述)。
为了充分利用物理资源、快速扩容同步节点、拥抱云原生,决定使用k8s部署otter。
otter的项目整体上自成一体,出于改造成本考虑,尽量在项目已有基础上,做一些适配,不改动源代码。
本文将重点分享对于otter适配k8s部署的改造过程,有不当之处,还请多多指教。
涉及到几个核心内容:
- otter基本架构
- dockerfile编写
- deployment编写
- 启动脚本改造
- K8s中固定ip/port访问
2.otter的基本架构
典型管理系统架构,manager(web管理)+node(工作节点)
- manager运行时推送同步配置到node节点
- node节点将同步状态反馈到manager上
- 基于zookeeper,解决分布式状态调度的,允许多node节点之间协同工作
- 基于Canal开源产品,获取数据库增量日志数据。当然,otter采用了canal的嵌入式模式,不是独立的canal节点。
基于以上部署架构,我们只需要将otter-manager和otter-node部署到k8s上。
尤其是otter-node,需要利用k8s实现节点快速水平扩展、计算性能弹性扩缩容。
2.Dockerfile编写
2.1 otter-manager的Dockerfile
otter-manager比较简单,包括几个步骤:
- 使用一个centos的基础镜像
- 设置时区
- 创建目录
- 拷贝下载好的manager.deployer-4.2.18到指定目录
- 使用启动startup-new.sh脚本启动(这里对原本的启动脚本做了一些改造,后文进行详述)
具体如下所示:
2.2 otter-node的Dockerfile
otter-node稍微有所不同,根据官方文档说明,需要安装aria2来做文件传输。
注意注意,由于aria2安装非常慢,因此,我们需要先安装aria2作为一个新的基础镜像,然后在新的基础镜像上构建otter-node镜像,能大大提高后续镜像构建速度。
新的基础镜像如下,命名为 registry.xxx.com/xxx/otter-node-base:1.0。
然后在此基础上构建新的otter-node镜像。
注意,otter-node的配置方式比较特殊,需要先在otter-admin上获取一个nid,然后才能运行一个otter-node。
所以,我们在dockerfile中以ARG 声明一个nid,然后在后续构建镜像的时候,通过 --docker-arg 传入nid具体的值。
当然,如果把nid看作一个配置文件的话,也可以用下文提到的ConfigMap的形式在Deployment中挂载进去
3.Deployment编写
什么是Deployment?
k8s的一个Deployment控制器为 Pods 和 ReplicaSets 提供声明式的更新能力。我们通过编写Deployment描述期望的目标状态,然后 Deployment 控制器更改Pods或者ReplicaSets的实际状态, 使其变为期望状态。
具体关于Deployment的知识不展开说明,可以参考k8s官方文档。
我们需要部署测试环境与生产环境两套集群,而无论是otter-manager还是otter-node,都依赖于读取 conf/otter.properties 作为配置。
因此,我们需要根据环境,修改不同的otter.properties。
那么,对于k8s部署来说,可以采用同一份镜像,然后在不同环境(k8s的不同namespace)中将otter.properties作为ConfigMap写入,最后通过volume的形式挂载到pod的指定路径上。
这里对几个名词做简单介绍,详细内容可以参考k8s官方文档。
- ConfigMap:一种 API 对象,用来将非机密性的数据保存到键值对中。使用时,Pods可以将其用作环境变量、命令行参数或者存储卷中的配置文件。(如果想存储的数据是机密的,可以使用 Secret,而不是ConfigMap)
- Volume:卷的核心是包含一些数据的一个目录,Pod 中的容器可以访问该目录。所采用的特定的卷类型将决定该目录如何形成的、使用何种介质保存数据以及目录中存放 的内容。使用卷时, 在 .spec.volumes 字段中设置为 Pod 提供的卷,并在 .spec.containers[*].volumeMounts 字段中声明卷在容器中的挂载位置。
所以,首先在指定环境(namespace中)创建configmap,以otter.properties作为key,以文件内容作为value。
具体命令如下
kubectl create configmap otter-manager-dev-config --from-file=otter.properties=conf/otter-dev.properties -n otter-system
- 在namespace为otter-system中创建一个名字为otter-manager-dev-config的ConfigMap,其中,以otter.properties作为key,以文件内容作为value。
产生的ConfigMap如下图所示
最后,将这个ConfigMap在Deployment中用volume进行引用,然后通过volumeMounts挂载到指定目录,Deployment具体如下所示。
这里需要特别注意volumeMounts的路径覆盖问题,需要在volumeMounts中配置subPath为具体文件名。