微信搜索【阿丸笔记】,关注Java/MySQL/中间件各系列原创实战笔记,干货满满。

k8s以及云原生相关概念近年来一直比较火热,阿丸最近搞了个相关项目,小结一下。

本文将重点分享阿里开源项目otter适配k8s部署的改造过程,其中的改造过程和技巧应该适用于将大多数开源项目改造到k8s进行部署。

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为具体文件名。

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的,这些技巧应该都能用上。

如果你有更好的一些方式和技巧分享,欢迎留言交流~~~

都看到最后了,原创不易,点个关注,点个赞吧~

文章持续更新,可以微信搜索「阿丸笔记 」第一时间阅读,回复【笔记】获取Canal、MySQL、HBase、JAVA实战笔记,回复【资料】获取一线大厂面试资料。

知识碎片重新梳理,构建Java知识图谱:github.com/saigu/JavaK…(历史文章查阅非常方便)

拥抱云原生,如何将开源项目用k8s部署?的更多相关文章

  1. 拥抱云原生 2.0 时代,Tapdata 入选阿里云首期云原生加速器!

      3月9日,阿里云首期云原生加速器官宣,Tapdata 突出重围,成功入选31 强,将与多家行业知名企业,携手阿里云共建云原生行业新生态,加速拥抱云原生新时代的无限潜能.   2021年,阿里云正式 ...

  2. 我发起了一个 用 物理服务器 和 .Net 平台 构建云平台 的 .Net 开源项目

    大家好 , 我发起了一个 用 物理服务器 和 .Net 平台 构建云平台 的 .Net 开源项目 . 对 , 用 物理服务器 和 .Net 平台 构建 云平台 . 通过 .Net 构建 分布式 计算集 ...

  3. Spring Boot 2.4.0 正式发布!全新的配置处理机制,拥抱云原生!

    2020年11月12日,Spring官方发布了Spring Boot 2.4.0 GA的公告. 在这个版本中增加了大量的新特性和改进,下面我们一起看看在这个重要版本中都有哪些值得关注的内容! 更新内容 ...

  4. Docker 开源项目之 registry - 部署 registry (注册表)服务器

    原文地址 在部署 registry 之前需要现在主机上安装 Docker.registry 实际上就是运行在 Docker 中的 registry 镜像的实例. 本主题提供关于部署和配置 regist ...

  5. Ambassador,云原生应用的“门神”

    目前,行业内基于云原生思想的开源项目,重点在于管理.控制微服务以及微服务架构下服务之间的通信问题.它们有效的解决了“服务异构化”.“动态化”.“多协议”场景所带来的east/west流量的管控问题,而 ...

  6. 专访 KubeVela 核心团队:如何简化云原生复杂环境下的应用交付和管理

    作者 | Infoq Tina 背景 12 月 9 日,在 2021 年 KubeCon 云原生技术峰会上,CNCF 开源项目 KubeVela 宣布推出了 1.2 版本. KubeVela 是一个简 ...

  7. SmartIDE v0.1.19 - 码云(Gitee)最有价值开源项目奖项、工作区策略、类虚拟机镜像VMLC、Server安装手册

    SmartIDE v0.1.19 (CLI Build 3909, Server Build 3890) 已经发布,本次Sprint主要完成2个重要特性,工作区策略和类虚拟机容器(VM Like Co ...

  8. Kubernetes 入门必备云原生发展简史

    作者|张磊 阿里云容器平台高级技术专家,CNCF 官方大使 "未来的软件一定是生长于云上的"这是云原生理念的最核心假设.而所谓"云原生",实际上就是在定义一条能 ...

  9. CNCF官方大使张磊:什么是云原生?

    作者|张磊 阿里云容器平台高级技术专家,CNCF 官方大使 编者说: 从 2015 年 Google 牵头成立 CNCF 以来,云原生技术开始进入公众的视线并取得快速的发展,到 2018 年包括 Go ...

随机推荐

  1. 【PYTEST】第一章常用命令

    pytest入门 安装pytest 运行pytest pytest常用命令 1. 安装pytest pip install pytest 2. 运行pytest 2.1 pytest默认搜索当前目录下 ...

  2. Httprunner初步学习

    一:简介 一直在技术博客上看到Httprunner测试框架,但始终不太明白这个框架的具体作用,今天就花点时间来初步学习了解一下. HttpRunner 是一款面向 HTTP(S) 协议的通用测试框架, ...

  3. Arcgis基于高程(DEM)计算地形湿度指数(TWI),以及坡度(Slope)度单位转换为弧度

    以30m*30m分辨率的图层为例 一.基于表面工具箱Surface计算Slope 1.如下图输入图层DEM,输出Slope 2.单位转换: Scale_slope=Slope*pi/180 二.基于水 ...

  4. spring boot 访问外部http请求

    以前 访问外部请求都要经过 要用 httpClient  需要专门写一个方法  来发送http请求   这个这里就不说了 网上一搜全都是现成的方法 springboot 实现外部http请求 是通过F ...

  5. 【2020.11.28提高组模拟】T1染色(color)

    [2020.11.28提高组模拟]T1染色(color) 题目 题目描述 给定 \(n\),你现在需要给整数 \(1\) 到 \(n\) 进行染色,使得对于所有的 \(1\leq i<j\leq ...

  6. 【Usaco 2009 Silver】JZOJ2020年9月19日提高B组T1 音乐节拍

    [Usaco 2009 Silver]JZOJ2020年9月19日提高B组T1 音乐节拍 题目 Description FJ准备教他的奶牛弹奏一首歌曲,歌曲由N(1<=N<=50,000) ...

  7. 第8.11节 Python类中记录实例变量属性的特殊变量__dict__

    一. 语法释义 调用方法:实例. __dict__属性 __dict__属性返回的是实例对象中当前已经定义的所有自定义实例变量的名和值,用字典存储,每个元素为一个"实例变量名:值" ...

  8. 团队作业4-Day4

    团队作业4-Day4 项目git地址 1. 站立式会议 2. 项目燃尽图 3. 适当的项目截图 4. 代码/文档签入记录(部分) 5. 每人每日总结 吴梓华:完成了排位模式与练习模式的界面实现,整合代 ...

  9. 第二篇 Scrum 冲刺博客

    一.站立式会议 1. 会议照片 2. 工作汇报 成员名称 昨日(23日)完成的工作 今天(24日)计划完成的工作 工作中遇到的困难 陈锐基 - 完成个人资料编辑功能- 对接获取表白动态的接口数据并渲染 ...

  10. Devpress (DxReport)使用ReportDesigner (一) 基本功能

    1. Devpress (DxReport)编辑 (1) 新建一个XtraReport. (2) 在报告上点右键添加元素:   元素说明: (1) 其中有报告头,报告尾,页头,页尾,组头,组尾,详细. ...