k8s中实现自动数据库初始化(mysql,postgresql)

版权声明:本文为博主原创文章,转载请注明来源。开发合作联系[email protected] https://blog.csdn.net/luanpeng825485697/article/details/86519991

全栈工程师开发手册 (作者:栾鹏)
架构系列文章

我们知道在代码里面创建数据库链接需要先有database, 但是我们刚刚部署的数据库可能还没有database或者没有指定权限的用户,这就要求我们在部署完数据库以后手动链接,创建数据库和用户. 有两种方式来实现自动化, 这里以mysql为例

通过环境变量实现

在k8s中部署mysql时,可以传环境变量指定,例如下面的yaml文件

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-mysql
  labels:
    app: my-mysql
    version: v1.0.0
spec:
  selector:
    matchLabels:
      app: my-mysql
      version: v1.0.0
  strategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: my-mysql
        version: v1.0.0
    spec:
      containers:
      - image: mysql:5.6
        name: my-mysql
        args:
          - "--ignore-db-dir=lost+found"
          - "--character-set-server=utf8"     #  指定字符编码
          - "--collation-server=utf8_general_ci"    #  指定字符编码
        env:
        - name: MYSQL_ROOT_PASSWORD    #  指定root用户的用户名
          value: introcks
        - name: MYSQL_PASSWORD     #  新建用户的用户名
          value: introcks
        - name: MYSQL_USER        # 新建的用户
          value: root
        - name: MYSQL_DATABASE    # 新建的数据库
          value: cloudai
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
        - name: config
          mountPath: /etc/mysql/mysql.conf.d/mysqld.cnf
          subPath: mysqld.cnf
          readOnly: False
      volumes:
      - name: data
        persistentVolumeClaim:
          claimName: mysql-pvc
      - name: config
        configMap:
          name: mysql-configmap

这样就能在创建的时候创建用户,密码,数据库和指定字符编码, 但是这种通过环境变量超过的有一个问题是操作内容有限. 下面我们来实现第二种方法.

init容器直接执行自定义的sql语句

我们可以添加一个init容器, 并将sql语句挂载进去, init容器中实现执行sql语句的功能. 这里我实现了一个, 镜像源码在github上: https://github.com/626626cdllp/k8s/tree/master/database-tools

不想重新制作的可以直接拉取luanpeng/lp:database-tools-1.0

镜像启动就会执行容器中/root/db_tools/script/文件夹下的所有sql文件. 所以我们只需要将sql语句,以configmap的形式挂载到这个目录下就行.

我们先来创建一个sql语句的configmap

apiVersion: v1
kind: ConfigMap
metadata:
  name: hive-metastore-database
  labels:
    app: yourapp_name
data:
  execute.sql: |-
    -- create database
    CREATE DATABASE IF NOT EXISTS mytable DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;
    -- create user and grant authorization
    GRANT ALL ON mytable.* TO 'luanpeng'@'%' IDENTIFIED BY '${IDENTIFIED}';

上面创建数据库,并将权限授予luanpeng用户.

下面就可以将这个sql语句挂载到init容器中

apiVersion: apps/v1
kind: Deployment
metadata:
  name: xxx
  labels:
    app: xxx
    version: v1.0.0
spec:
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: xxx
      version: v1.0.0
  template:
    metadata:
      labels:
        app: xxx
        version: v1.0.0
    spec:
      initContainers:
        - name: init-dababase
          image:  luanpeng/lp:database-tools-1.0
          env:
            - name: DRIVER_NAME      # 链接不同的数据库,使用的驱动名
              value: "com.mysql.jdbc.Driver"
            - name: URL                    # 链接地址
              value: "jdbc:mysql://hive-metadata-mysql-service:3306/mysql?useUnicode=true&characterEncoding=utf8&useSSL=false"
            - name: USERNAME       # 用户名
              value: "root"
            - name: PASSWORD      # 密码
              value: "admin"
            - name: IDENTIFIED
              value: "admin"
          volumeMounts:
            - name: init-dababase-volume
              mountPath: /root/db_tools/script   # 必须挂载到该目录
      containers:
         ......
      volumes:
        - name: init-dababase-volume
          configMap:
            name: hive-metastore-database

这样要实现更加复杂的初始化工作就可以直接在sql里面写了.

注意: 如果init容器运行失败,则会不运行后续的容器,我们可以通过设置sql语句,争取不报错

init容器

在 Pod 启动过程中,Init 容器会按顺序在网络和数据卷初始化之后启动。 每个容器必须在下一个容器启动之前成功退出。 如果由于运行时或失败退出,导致容器启动失败,它会根据 Pod 的 restartPolicy 指定的策略进行重试。 然而,如果 Pod 的 restartPolicy 设置为 Always,Init 容器失败时会使用 RestartPolicy 策略。

在所有的 Init 容器没有成功之前,Pod 将不会变成 Ready 状态。 Init 容器的端口将不会在 Service 中进行聚集。 正在初始化中的 Pod 处于 Pending 状态,但应该会将条件 Initializing 设置为 true。

如果 Pod 重启,所有 Init 容器必须重新执行。

对 Init 容器 spec 的修改,被限制在容器 image 字段中。 更改 Init 容器的 image 字段,等价于重启该 Pod。

因为 Init 容器可能会被重启、重试或者重新执行,所以 Init 容器的代码应该是幂等的。 特别地,被写到 EmptyDirs 中文件的代码,应该对输出文件可能已经存在做好准备。

Init 容器具有应用容器的所有字段。 然而 Kubernetes 禁止使用 readinessProbe,因为 Init 容器不能够定义不同于完成(completion)的就绪(readiness)。 这会在验证过程中强制执行。

在 Pod 上使用 activeDeadlineSeconds,在容器上使用 livenessProbe,这样能够避免 Init 容器一直失败。 这就为 Init 容器活跃设置了一个期限。

在 Pod 中的每个 app 和 Init 容器的名称必须唯一;与任何其它容器共享同一个名称,会在验证时抛出错误。

猜你喜欢

转载自blog.csdn.net/luanpeng825485697/article/details/86519991
今日推荐