Skip to content

goInception 的使用

文档地址:https://hanchuanchuan.github.io/goInception/zh/
goInception是一个集审核、执行、备份及生成回滚语句于一身的MySQL运维工具, 通过对执行SQL的语法解析,返回基于自定义规则的审核结果,并提供执行和备份及生成回滚语句的功能。

运维平台集成

  • 最开始是使用 Inception
  • 后面为了支持 mysql 的 json 数据类型,升级到使用 goInception 了
  • 从 Inception 升级到 goInception 改动的地方很少,几乎可以说是无缝切换
  • 直接使用 goInception 的二进制包运行,非常简单
  • 根据公司内部数据库规范,更新对应的配置项即可

海外数据库的挑战

运维平台集成 goInception 进行 MySQL 数据库的审核上线功能,其中涉及到三个对象:

  1. 运维平台
  2. goInception 中间件
  3. MySQL 数据库

三者之间存在隐形的条件:网络互通

随着新增的海外业务,海外数据库打破了网络互通的条件;内网打通也面临挑战

解决方案

当前结构简要

  • 运维平台部署于国内阿里云
  • 海外数据库位于美区 AWS
  • 业务服务部署于 AWS k8s 中

方案

  1. 将 goInception 部署于数据库对应的 k8s 中(goInception 官方有提供 docker 镜像)
  2. 运维平台通过 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}