goInception 的使用
文档地址:https://hanchuanchuan.github.io/goInception/zh/
goInception是一个集审核、执行、备份及生成回滚语句于一身的MySQL运维工具, 通过对执行SQL的语法解析,返回基于自定义规则的审核结果,并提供执行和备份及生成回滚语句的功能。
运维平台集成
- 最开始是使用 Inception 的
- 后面为了支持 mysql 的 json 数据类型,升级到使用 goInception 了
- 从 Inception 升级到 goInception 改动的地方很少,几乎可以说是无缝切换
- 直接使用 goInception 的二进制包运行,非常简单
- 根据公司内部数据库规范,更新对应的配置项即可
海外数据库的挑战
运维平台集成 goInception 进行 MySQL 数据库的审核上线功能,其中涉及到三个对象:
- 运维平台
- goInception 中间件
- MySQL 数据库
三者之间存在隐形的条件:网络互通
随着新增的海外业务,海外数据库打破了网络互通的条件;内网打通也面临挑战
解决方案
当前结构简要
- 运维平台部署于国内阿里云
- 海外数据库位于美区 AWS
- 业务服务部署于 AWS k8s 中
方案
- 将 goInception 部署于数据库对应的 k8s 中(goInception 官方有提供 docker 镜像)
- 运维平台通过 k8s api 在 pod 中执行命令的方式来调用 goInception
网络
- 公网:运维平台到 k8s 里头的 goInception (goInception 本身是在内网中)
- 内网:goInception 到目标数据库
最终实现
- goInception 部署于 k8s 中,配置文件使用 configmap 挂载
- goInception pod 中有两个容器,一个是 goInception,另一个是 python3.10
- python 容器用来调用 goInception,使用 pymysql 来连接调用,可以和之前的国内使用 goInception 的代码保持一致
- 最开始没有计划使用 python 容器,是直接打算使用 mysqlsh 命令来调用 goInception 的;但是实际使用测试中发现 sql 语句在 linux 命令行中会存在转义、继而导致命令行语法问题。
- 最终改用添加 python 容器来运行,一可以避免重新解析 goInception 的审核结果,二是还可以直接复用之前的代码
- python 容器安装 pymysql 可配置在容器启动后立即运行;使用 pymysql 的脚本使用 configmap 挂载
- sql 语句作为参数传递给 python 脚本时,同样存在命令行中转义报错问题。最终使用 base64 编码传递、脚本中接收后解码使用解决
代码
bash
#!/bin/bash
# 创建 goinception 配置文件 configmap
kubectl create configmap goinception-config --from-file=./config.toml -n op
# 创建 sql.py 文件 configmap
kubectl create configmap python-sql --from-file=./sql.py -n op
# 创建 goinception 容器
kubectl apply -f goinception.yaml
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: '3'
generation: 3
labels:
app: goinception
kubepi.org/name: goinception
name: goinception
namespace: op
spec:
progressDeadlineSeconds: 600
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: goinception
kubepi.org/name: goinception
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
labels:
app: goinception
kubepi.org/name: goinception
spec:
affinity: {}
containers:
- image: 'hanchuanchuan/goinception:v1.3.0'
imagePullPolicy: IfNotPresent
lifecycle: {}
name: goinception
resources:
limits:
cpu: '1'
memory: 1Gi
securityContext:
capabilities: {}
seLinuxOptions: {}
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /etc/config.toml
name: configmap-volume
subPath: config.toml
- args:
- '-c'
- while true; do date; sleep 10; done
command:
- /bin/sh
image: 'python:3.10.12'
imagePullPolicy: IfNotPresent
lifecycle:
postStart:
exec:
command:
- /bin/sh
- '-c'
- pip install pymysql; pip list
name: python
resources:
limits:
cpu: '1'
memory: 1Gi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- mountPath: /sql.py
name: configmap-pymysql
subPath: sql.py
dnsConfig: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
schedulerName: default-scheduler
securityContext:
seLinuxOptions: {}
terminationGracePeriodSeconds: 30
volumes:
- configMap:
defaultMode: 420
name: goinception-config
name: configmap-volume
- configMap:
defaultMode: 420
name: python-sql
name: configmap-pymysql
python
import base64
import json
import pymysql
import re
import sys
import traceback
"""
通过输出将结果给到调用方(pod)
不能添加其它输出
"""
sql = sys.argv[1]
info = re.findall(r"b'(.*?)'", sql)
sql = info[0]
sql = base64.b64decode(sql).decode()
inception_conn = {
'host': '127.0.0.1',
'user': '',
'passwd': '',
'port': 4000,
}
conn = pymysql.connect(**inception_conn)
try:
with conn.cursor() as cur:
cur.execute(sql)
res = cur.fetchall()
res_byte = json.dumps(res).encode('utf-8')
print(base64.b64encode(res_byte))
except Exception:
print(traceback.format_exc())
finally:
conn.close()
- config.toml 为 goInception 的配置文件
- sql.py 为 pymysql 调用 goInception 的脚本
- 最终审核的执行就是在 pod 中运行
python sql.py {sql}