k8s挂载目录_拥抱云原生,如何将开源项目用k8s部署?

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

53b8a137f5838ab534e3f75359f495f0.png

本文将重点分享阿里开源项目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的基本架构

e1b991abf5a4532b4ebae33db67f4fb0.png

典型管理系统架构,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脚本启动(这里对原本的启动脚本做了一些改造,后文进行详述)

具体如下所示:

681fa5b85d3a4e1d5768e34369039c05.png

2.2 otter-node的Dockerfile

otter-node稍微有所不同,根据官方文档说明,需要安装aria2来做文件传输。

注意注意,由于aria2安装非常慢,因此,我们需要先安装aria2作为一个新的基础镜像,然后在新的基础镜像上构建otter-node镜像,能大大提高后续镜像构建速度。

新的基础镜像如下,命名为 http://registry.xxx.com/xxx/otter-node-base:1.0

7e908cf924732a182317fbf10c06cf30.png

然后在此基础上构建新的otter-node镜像。

54c0f074993c1e46e94f38d98dcb4634.png

注意,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如下图所示

d7911cf4f08e12c378564acc4467a3b3.png

然后,将这个configmap在Deployment中用volume进行引用,然后通过volumeMounts挂载到指定目录,Deployment具体如下所示。

1056fb6acd1ce2441921175f2d778da5.png

这里需要特别注意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号进程也不会结束。

具体修改如下:

cd672342252639b62a1bce44a55e6b36.png

最终pod中的进程如图所示

3d77cc15345833f72ee7b9074bc498f1.png
  • 1号进程是启动脚本
  • 1号进程的子进程是otter的java应用进程(前台进程)

4.2 虚拟机大小自定义配置

由于otter项目中,将jvm的启动参数配置在了start.sh中,不方便进行手动配置。

因此,将start.sh的配置jvm参数的逻辑注释掉,采用自己配置的环境变量JAVA_OPTIONS进行注入。

5b89f96b77577b49ea089bdb6eb1367e.png

这个环境变量的注入方式也比较简单,就是在上面的Deployment中的env配置的(蓝色框部分),方便以后手动修改jvm参数大小而不用修改镜像。

5fc3a238893ec1dd9daa7acbc27be90b.png

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,正如这个名字所示,在所有节点(虚拟机)上开放一个特定端口,任何发送到该端口的流量都被转发到对应服务。如下图所示。

069f6a3849df45a1a57c862e06379ccb.png

在上面的配置中,可以使用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文件吧。

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

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

都看到最后了,原创不易,点个关注,点个赞吧~
知识碎片重新梳理,构建Java知识图谱:github.com/saigu/JavaK…(历史文章查阅非常方便)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/472195.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 1870. 准时到达的列车最小时速(二分查找)

文章目录1. 题目2. 解题2.1 模拟超时2.2 二分查找1. 题目 给你一个浮点数 hour ,表示你到达办公室可用的总通勤时间。 要到达办公室,你必须按给定次序乘坐 n 趟列车。 另给你一个长度为 n 的整数数组 dist ,其中 dist[i] 表示第 i 趟列车的行…

【Python基础知识-pycharm版】第十一节-文件操作(IO技术)

第十一节-文件操作(IO技术)文本文件和二进制文件文件操作相关模块概述创建文件对象 open()文本文件的写入基本的文件写入操作常用编码介绍ASCIIISO8859-1GB2312,GBK,GB18030中文乱码问题write()/writelines()写入数据close()关闭文件流with 语句(上下文管…

LeetCode 1871. 跳跃游戏 VII(贪心)

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的二进制字符串 s 和两个整数 minJump 和 maxJump 。 一开始,你在下标 0 处,且该位置的值一定为 0 。 当同时满足如下条件时,你可以从下标 i 移动到下标 j 处: i minJump …

pcb外观维修_「维修案例」泰克AFG3021函数任意波形发生器故障维修

在产品调试的过程中,大多数的电路需要输入某种幅度随时间变化的信号,在这样的应用场景中,一个完整的测试测量系统一般会包含激励源,被测件和采集仪器三个部分。采集仪器通常使用的是示波器和逻辑分析仪,而信号源在系统…

设计模式--迭代器模式

实验18:迭代器模式 本次实验属于模仿型实验,通过本次实验学生将掌握以下内容: 1、理解迭代器模式的动机,掌握该模式的结构; 2、能够利用迭代器模式解决实际问题。 [实验任务]:JAVA和C常见数据结构迭代…

4k视频分辨率的码流_8K电视来了!但是8K视频仍很遥远

本届CES上,8K电视的集体发布可谓一大亮点,索尼、LG、TCL、三星等厂商纷纷推出8K电视。不光如此,本届CES上夏普突如其来的展示了一款具备8K视频拍摄功能的M43相机,这一点着实是出乎意料。今天我们就来讨论一下,在8K电视…

LeetCode 1707. 与数组中元素的最大异或值(Trie树)

文章目录1. 题目2. 解题1. 题目 给你一个由非负整数组成的数组 nums 。另有一个查询数组 queries ,其中 queries[i] [xi, mi] 。 第 i 个查询的答案是 xi 和任何 nums 数组中不超过 mi 的元素按位异或(XOR)得到的最大值。 换句话说&#x…

我的爬虫第一天

爬虫一个简单的爬虫:1.安装request2.测试是否安装成功3.新建项目4.使用requests请求网页4.如何用python解析网页源码5.简单的保存数据的方法一个简单的爬虫: 1.安装request pip install requests2.测试是否安装成功 输入python import requests不报…

qr分解求线性方程组_计算方法/数值分析第三章 线性方程组的数值解法

主要内容:1、引言2、高斯消去法3、直接分解法4、解线性方程组的迭代法5、向量范数、矩阵范数及迭代法的收敛性第一节 引言用克拉姆求解线性方程组第二节 高斯消去法高斯消去法是一种古老的直接法,其基本思想是通过消元将线性方程组的求解问题转化成三角形…

python 执行完成后,cmd窗口自动关闭

一般脚本运行完需要点击一下 在代码最后添加以下内容即可自动关闭cmd: import os import time time.sleep(1) # 方便展示,可删除 os.system("taskkill /f /im cmd.exe") # 关闭cmd窗口

txt文件可存储最大值_Verilog边码边学:十六进制文件读取$readmemh

系统任务$readmemh读取十六进制文件。$readmemh的作用是将文件中的数据一次性的读入某个数组中,然后可以依次从数组中取出单个的数据进行处理。读取的内容只包括空白位置(空格、换行、制表格)、注释行、十六进制的数字。语法结构中的起始地址与终止地址可省略。【语…

什么叫诚实_他爱不爱你,身体最诚实

文字:嘉一 声音:三三有位听友给我发私信说:“他看我的眼神变了,也不喜欢和我说话了,更懒得为我做任何事了,这段感情真的没意思了。”我回她:“一个人爱不爱你,身体最诚实。嘴巴可以…

【机器学习-数据科学】第一节:numpypandas

numpy&pandas安装numpy&pandasarray创建numpy的基础运算numpy的索引numpy的 array 合并numpy的 array分割numpy的 copy & deep copy安装numpy&pandas import numpy as np arraynp.array([[1,2,3],[2,3,4]])# 将数组转化为矩阵 print(array) #打印矩阵 print(nu…

【机器学习-数据科学】第二节:ipython开发环境搭建以及pandas快速入门

ipython开发环境搭建以及pandas快速入门0.开发环境搭建技巧网页版ipython:ipython notebooknumpy1.pandas 快速入门一导入创建对象2. pandas 快速入门二空数据处理apply的用法count和mode函数数据合并3. pandas 快速入门三数据整形数据透视时间序列数据可视化数据载…

pytorch图像和张量的相互转换_Day107:Pytorch张量类型的构建与相互转换

张量的作用Pytorch的数据类型为各式各样的Tensor,Tensor可以理解为高维矩阵(与Numpy中的Array类似)通过使用Type函数可以查看变量类型。一CPU张量类型Pytorch中的tensor包括七种CPU张量类型和八种GPU张量类型,这里我们就只讲解一下CPU中的,GP…

漂亮的html页面源码_爬虫数据分析之html

1、 htmlhtml 不是一种编程语言,而是一种标记语言,是制作网页所必须的,你在浏览器里看到的每一个页面,不论简单还是复杂,都是用html编写的,包括你现在看到的这篇文章。用html写一个简单的页面,是…

LeetCode 1864. 构成交替字符串需要的最小交换次数

文章目录1. 题目2. 解题1. 题目 给你一个二进制字符串 s ,现需要将其转化为一个 交替字符串 。 请你计算并返回转化所需的 最小 字符交换次数,如果无法完成转化,返回 -1 。 交替字符串 是指:相邻字符之间不存在相等情况的字符串…

【机器学习-数据科学】第三节:数据分析实例 分析MovieLens电影数据

数据分析实例 分析MovieLens电影数据导入数据数据合并按性别查看各个电影的平均评分活跃电影排行榜电影投票数据 grouplens.org/datasets/movielens 把文件放到这个路径下 导入数据 数据合并 按性别查看各个电影的平均评分 查看男女评分差别最大的 按照diff去排序 找出分歧…

vue路由切换组件没有加载_Vue面试题: 如何实现路由懒加载?

非懒加载import List from /components/list.vue const router new VueRouter({routes: [{ path: /list, component: List }] })方案一(常用)const List () > import(/components/list.vue) const router new VueRouter({routes: [{ path: /list, component: List }] })方…

LeetCode 1865. 找出和为指定值的下标对(哈希)

文章目录1. 题目2. 解题1. 题目 给你两个整数数组 nums1 和 nums2 ,请你实现一个支持下述两类查询的数据结构: 累加 ,将一个正整数加到 nums2 中指定下标对应元素上。计数 ,统计满足 nums1[i] nums2[j] 等于指定值的下标对 (i,…