关于数据库:想提高运维效率那就把MySQL数据库部署到Kubernetes-集群中

22次阅读

共计 17054 个字符,预计需要花费 43 分钟才能阅读完成。

摘要:Kubernetes 很多看起来比拟“繁琐”的设计的次要目标,都是心愿为开发者提供更多的“可扩展性”,给使用者带来更多的“稳定性”和“安全感”。

本文分享自华为云社区《如何在 Kubernetes 集群中搭建一个简单的 MySQL 数据库?》,作者:zuozewei。

前言

理论生产环境中,为了稳固和高可用,运维团队个别不会把 MySQL 数据库部署在 Kubernetes 集群中,个别是用云厂商的数据库或者本人在高性能机器(如裸金属服务器)上搭建。

然而,对于测试开发环境,咱们齐全能够把 MySQL 部署到各自的 Kubernetes 集群中, 十分有助于晋升运维效率,而且还有助于 Kubernetes 应用的教训积攒。

繁难部署

​如下所示,咱们仅需设置 root 用户明码(环境变量 MYSQL_ROOT_PASSWORD),便可轻松的应用 MySQL 官网镜像构建一个 MySQL 数据库。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: mysql-min
  name: mysql-min
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql-min
  template:
    metadata:
      labels:
        app: mysql-min
    spec:
      containers:
      - image: centos/mysql-57-centos7:latest
        name: mysql-min
        imagePullPolicy: IfNotPresent
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: admin@123

​创立一 Service 以便集群内外均可拜访数据库,其中集群外需通过 nodePort 设置的 30336 端口拜访。

apiVersion: v1
kind: Service
metadata:
  labels:
    app: mysql-min
    release: mysql-min
  name: mysql-min
  namespace: default
spec:
  ports:
  - name: mysql
    port: 3306
    protocol: TCP
    nodePort: 30336
    targetPort: mysql
  selector:
    app: mysql-min
  #目前 sessionAffinity 能够提供 "None""ClientIP" 两种设定:
  #None: 以 round robin 的形式轮询上面的 Pods。#ClientIP: 以 client ip 的形式固定 request 到同一台机器。sessionAffinity: None
  type: NodePort
#status:
#  loadBalancer: {}

接着,拜访数据库并验证其运行失常:

# kubectl get pod   # 以后 Pod 名称
NAME                         READY     STATUS    RESTARTS   AGE
mysql-min-5b5668c448-t44ml   1/1       Running   0          3h

# 通过本机拜访
# kubectl exec -it mysql-min-5b5668c448-t44ml -- mysql -uroot -padmin@123
mysql> select 1;
+---+
| 1 |
+---+
| 1 |
+---+

# 集群外部通过 mysql service 拜访:# kubectl exec -it mysql-min-5b5668c448-t44ml -- mysql -uroot -padmin@123 -hmysql

mysql> select now();
+---------------------+
| now()               |
+---------------------+
| 2021-03-13 07:19:14 |
+---------------------+

# 集群内部,可通过任何一个 K8S 节点拜访数据库:# mysql -uroot -padmin@123 -hworker-1 -P30336 

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+

扩大部署

长久化存储

若要确保 MySQL 重启后数据依然存在,咱们需为其配置可长久化存储,我这里的试验环境应用的是 Local Persistent Volume,也就是说,我心愿 Kubernetes 可能间接应用宿主机上的本地磁盘目录,而不依赖于近程存储服务,来提供“长久化”的容器 Volume。这样做的益处很显著,因为这个 Volume 间接应用的是本地磁盘,尤其是 SSD 盘,它的读写性能相比于大多数近程存储来说,要好得多。这个需要对本地物理服务器部署的公有 Kubernetes 集群来说,十分常见。

值得指出的是其次,相比于失常的 PV,一旦这些节点宕机且不能复原时,本地存储 Volume 的数据就可能失落。这就要求应用 其的利用必须具备数据备份和复原的能力,容许你把这些数据定时备份在其余地位。

不难想象,Local Persistent Volume 的设计,次要面临两个难点。

第一个难点在于:如何把本地磁盘形象成 PV。

可能你会说,Local Persistent Volume 不就等同于 hostPath 加 NodeAffinity 吗?

比方,一个 Pod 能够申明应用类型为 Local 的 PV,而这个 PV 其实就是一个 hostPath 类型的 Volume。如果这个 hostPath 对应的目录,曾经在节点 A 上被当时创立好了。那么,我只须要再给这个 Pod 加上一个 nodeAffinity=nodeA,不就能够应用这个 Volume 了吗?

事实上,你绝不应该把一个宿主机上的目录当作 PV 应用。这是因为,这种本地目录的存储行为齐全不可控,它所在的磁盘随时都可能被利用写满,甚至造成整个宿主机宕机。而且,不同的本地目录之间也不足哪怕最根底的 I/O 隔离机制。

所以,一个 本地存储 Volume 对应的存储介质,肯定是一块额定挂载在宿主机的磁盘或者块设施(“额定”的意思是,它不应该是宿主机根目录所应用的主硬盘)。这个准则,咱们能够称为“ 一个 PV 一块盘 ”。

第二个难点在于:调度器如何保障 Pod 始终能被正确地调度到它所申请的本地 Volume 所在的节点上呢?

造成这个问题的起因在于,对于惯例的 PV 来说,Kubernetes 都是先调度 Pod 到某个节点上,而后,再通过“两阶段解决”来“长久化”这台机器上的 Volume 目录,进而实现 Volume 目录与容器的绑定挂载。

可是,对于 Local PV 来说,节点上可供使用的磁盘(或者块设施),必须是运维人员提前准备好的。它们在不同节点上的挂载状况能够齐全不同,甚至有的节点能够没这种磁盘。

所以,这时候,调度器就必须可能晓得所有节点与 Local Persistent Volume 对应的磁盘的关联关系,而后依据这个信息来调度 Pod。

这个准则,咱们能够称为“在调度的时候思考 Volume 散布”。在 Kubernetes 的调度器里,有一个叫作 VolumeBindingChecker 的过滤条件专门负责这个事件。在 Kubernetes v1.11 中,这个过滤条件曾经默认开启了。

基于上述讲述,在开始应用 Local Persistent Volume 之前,你首先须要在集群里配置好磁盘或者块设施。在私有云上,这个操作等同于给虚拟机额定挂载一个磁盘,比方 GCE 的 Local SSD 类型的磁盘就是一个典型例子。

而在咱们部署的公有环境中,你有两种方法来实现这个步骤。

  • 第一种,当然就是给你的宿主机挂载并格式化一个可用的本地磁盘,这也是最惯例的操作;
  • 第二种,对于试验环境,你其实能够在宿主机上挂载几个 RAM Disk(内存盘)来模仿本地磁盘。

接下来,我会应用第二种办法,在咱们之前部署的 Kubernetes 集群上进行实际。首先,在名叫 node-1 的宿主机上创立一个挂载点,比方 /mnt/disks;而后,用几个 RAM Disk 来模仿本地磁盘,如下所示:

# 在 node- 1 上执行
$ mkdir /mnt/disks
$ for vol in vol1 vol2 vol3; do
    mkdir /mnt/disks/$vol
    mount -t tmpfs $vol /mnt/disks/$vol
done

须要留神的是,如果你心愿其余节点也能反对 Local Persistent Volume 的话,那就须要为它们也执行上述操作,并且确保这些磁盘的名字(vol1、vol2 等)都不反复。接下来,咱们就能够为这些本地磁盘定义对应的 PV 了,如下所示:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-min-pv-local
  namespace: default
spec:
  capacity:
    storage: 5Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  storageClassName: "mysql-min-storageclass-local"
  persistentVolumeReclaimPolicy: Retain
  #示意应用本地存储
  local:
    path: /mnt/disks/vol1
  #应用 local pv 时必须定义 nodeAffinity,Kubernetes Scheduler 须要应用 PV 的 nodeAffinity 形容信息来保障 Pod 可能调度到有对应 local volume 的 Node 上。#创立 local PV 之前,你须要先保障有对应的 storageClass 曾经创立。nodeAffinity:
    required:
      nodeSelectorTerms:
      - matchExpressions:
        - key: kubernetes.io/hostname
          operator: In
          values:
          # pod 须要分不到的主机名,这台主机上开启了 local-pv 资源。- node-1

能够看到,这个 PV 的定义里:local 字段,指定了它是一个 Local Persistent Volume;而 path 字段,指定的正是这个 PV 对应的本地磁盘的门路,即:/mnt/disks/vol1。

当然了,这也就意味着如果 Pod 要想应用这个 PV,那它就必须运行在 node-1 上。所以,在这个 PV 的定义里,须要有一个 nodeAffinity 字段指定 node-1 这个节点的名字。这样,调度器在调度 Pod 的时候,就可能晓得一个 PV 与节点的对应关系,从而做出正确的抉择。这正是 Kubernetes 实现“在调度的时候就思考 Volume 散布”的次要办法。

接下来要创立一个 StorageClass 来形容这个 PV,如下所示:

kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: mysql-min-storageclass-local
#指定存储类的供应者, 比方 aws, nfs 等,具体取值参考官网阐明。#存储类有一个供应者的参数域,此参数域决定 PV 应用什么存储卷插件。参数必须进行设置
#因为 demo 中应用的是本地存储,所以这里写 kubernetes.io/no-provisioner.
provisioner: kubernetes.io/no-provisioner
#volumeBindingMode 参数将提早 PVC 绑定,直到 pod 被调度。volumeBindingMode: WaitForFirstConsumer

这个 StorageClass 的名字,叫作 local-storage。须要留神的是,在它的 provisioner 字段,咱们指定的是 no-provisioner。这是因为 Local Persistent Volume 目前尚不反对 Dynamic Provisioning,所以它没方法在用户创立 PVC 的时候,就主动创立出对应的 PV。也就是说,咱们后面创立 PV 的操作,是不能够省略的。

与此同时,这个 StorageClass 还定义了一个 volumeBindingMode=WaitForFirstConsumer 的属性。它是 Local Persistent Volume 里一个十分重要的个性,即:提早绑定。

通过这个提早绑定机制,本来实时产生的 PVC 和 PV 的绑定过程,就被提早到了 Pod 第一次调度的时候在调度器中进行,从而保障了这个绑定后果不会影响 Pod 的失常调度。

接下来,咱们只须要定义一个十分一般的 PVC,就能够让 Pod 应用到下面定义好的 Local Persistent Volume 了,如下所示:

apiVersion: v1
items:
- apiVersion: v1
  kind: PersistentVolumeClaim
  metadata:
    #当启用 PVC 爱护 alpha 性能时,如果用户删除了一个 pod 正在应用的 PVC,则该 PVC 不会被立刻删除。PVC 的删除将被推延,直到 PVC 不再被任何 pod 应用。#能够看到,当 PVC 的状态为 Teminatiing 时,PVC 受到爱护,Finalizers 列表中蕴含 kubernetes.io/pvc-protection:finalizers:
    - kubernetes.io/pvc-protection
    labels:
      app: mysql-min
      release: mysql-min
    name: mysql-min
    namespace: default
  spec:
    #PV 的拜访模式(accessModes)有三种:#ReadWriteOnce(RWO):是最根本的形式,可读可写,但只反对被单个 Pod 挂载。#ReadOnlyMany(ROX):能够以只读的形式被多个 Pod 挂载。#ReadWriteMany(RWX):这种存储能够以读写的形式被多个 Pod 共享。accessModes:
    - ReadWriteOnce
    resources:
      requests:
        storage: 10Gi
    storageClassName: mysql-min-storageclass-local
    #示意应用本地磁盘,理论生产中个别都应用 nfs。volumeMode: Filesystem
    volumeName: mysql-min-pv-local
#  status:
#    accessModes:
#    - ReadWriteOnce
#    capacity:
#      storage: 1Gi
kind: List

能够看到,这个 PVC 没有任何特地的中央。惟一须要留神的是,它申明的 storageClassName 是 mysql-min-storageclass-local。所以,未来 Kubernetes 的 Volume Controller 看到这个 PVC 的时候,不会为它进行绑定操作。

最初,咱们创立 Local Persistent Volume 资源文件:

kubectl apply -f mysql-min-pv-local.yaml
kubectl apply -f mysql-min-storageclass-local.yaml
kubectl apply -f mysql-min-pvc.yaml

而后,调整 Deploy 并挂载卷:

spec:
    containers:
    - image: centos/mysql-57-centos7:latest
...
      volumeMounts:
      - name: data
        mountPath: /var/lib/mysql
    volumes:
    - name: data
      persistentVolumeClaim:
        claimName: mysql-min

自定义配置文件

通过创立 configmap 并挂载到容器中,咱们可自定义 MySQL 配置文件。如下所示,名为 mysql-config 的 cm 蕴含一个 my.cnf 文件:

apiVersion: v1
kind: ConfigMap
metadata:
  name: mysql-config
data:
  my.cnf: |
    [mysqld]
    default_storage_engine=innodb
    skip_external_locking
    lower_case_table_names=1
    skip_host_cache
    skip_name_resolve
    max_connections=2000
    innodb_buffer_pool_size=8589934592
    init_connect='SET collation_connection = utf8_unicode_ci'
    init_connect='SET NAMES utf8'
    character-set-server=utf8
    collation-server=utf8_unicode_ci
    skip-character-set-client-handshake
    query_cache_type=0
    innodb_flush_log_at_trx_commit = 0
    sync_binlog = 0
    query_cache_size = 104857600
    slow_query_log =1
    slow_query_log_file=/var/lib/mysql/slow-query.log
    log-error=/var/lib/mysql/mysql.err
    long_query_time = 0.02
    table_open_cache_instances=16
    table_open_cache = 6000
    skip-grant-tables
    sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

将 configmap 挂载到容器内:

    spec:
...
      containers:
      - image: centos/mysql-57-centos7:latest
...
        volumeMounts:
        - name: mysql-config
          mountPath: /etc/my.cnf.d/my.cnf
          subPath: my.cnf
...
      volumes:
      - name: mysql-config
        - name: mysql-config
          configMap:
            name: mysql-config
...

设置容器时区

最傻瓜也最不便的解决形式,设置宿主机时区和工夫文件与容器的映射。

    spec:
...
      containers:
      - image: centos/mysql-57-centos7:latest
...
        volumeMounts:
        - name: localtime
          readOnly: true
          mountPath: /etc/localtime
...
      volumes:
       - name: localtime
         hostPath:
           type: File
           path: /etc/localtime
...

加密敏感数据

用户明码等敏感数据以 Secret 加密保留,而后被 Deployment 通过 volume 挂载或环境变量援用。如本例,咱们创立 root、user 用户,将用户的明码加密保留:

apiVersion: v1
data:
  #将 mysql 数据库的所有 user 的 password 配置到 secret,对立治理
  mysql-password: YWRtaW4=
  mysql-root-password: OVplTmswRGdoSA==
kind: Secret
metadata:
  labels:
    app: mysql-min
    release: mysql-min
  name: mysql-min
  namespace: default
#Secret 有三种类型:#Opaque:base64 编码格局的 Secret,用来存储明码、密钥等;但数据也通过 base64 –decode 解码失去原始数据,所有加密性很弱。#kubernetes.io/dockerconfigjson:用来存储公有 docker registry 的认证信息。#kubernetes.io/service-account-token:用于被 serviceaccount 援用。serviceaccout 创立时 Kubernetes 会默认创立对应的 secret。Pod 如果应用了 serviceaccount,对应的 secret 会主动挂载到 Pod 目录 /run/secrets/ kubernetes.io/serviceaccount 中。type: Opaque

Secret 创立实现后,咱们将用户明文明码从 Deployment 去除,采纳环境变量形式援用 Secret 数据,参见如下 Yaml 批改:

  • root 用户及 MYSQL_USER 用户,其明码均通过 secretKeyRef 从 secret 获取。
    spec:

    ...
        containers:
        - image: centos/mysql-57-centos7:latest
          name: mysql-min
          imagePullPolicy: IfNotPresent
          env:
             #password 存储在 secret 中
             - name: MYSQL_ROOT_PASSWORD
               valueFrom:
                 secretKeyRef:
                   key: mysql-root-password
                   name: mysql-min
             - name: MYSQL_PASSWORD
               valueFrom:
                 secretKeyRef:
                   key: mysql-password
                   name: mysql-min
             - name: MYSQL_USER
               value: zuozewei

    容器健康检查

    K8S 镜像控制器可通过 livenessProbe 判断容器是否异样,进而决定是否重建容器;而 Service 服务可通过 readinessProbe 判断容器服务是否失常,从而确保服务可用性。

​本例配置的 livenessProbe 与 readinessProbe 是一样的,即间断 3 次查询数据库失败,则定义为异样。对 livenessProbe 与 readinessProbe 具体用法,不在本文的探讨范畴内,可参考 K8S 官网文档:

  • Configure Liveness and Readiness Probes
  • Pod Lifecycle
spec:
      containers:
          image: centos/mysql-57-centos7:latest
...
          #kubelet 应用 liveness probe(存活探针)来确定何时重启容器。例如,当应用程序处于运行状态但无奈做进一步操作,liveness 探针将捕捉到 deadlock,重启处于该状态下的容器,使应用程序在存在 bug 的状况下仍然可能持续运行上来
          livenessProbe:
            exec:
              command:
                - /bin/sh
                - "-c"
                - MYSQL_PWD="${MYSQL_ROOT_PASSWORD}"
                - mysql -h 127.0.0.1 -u root -e "SELECT 1"
            failureThreshold: 3 #探测胜利后,起码间断探测失败多少次才被认定为失败。默认是 3。最小值是 1。initialDelaySeconds: 30 #容器启动后第一次执行探测是须要期待多少秒。periodSeconds: 10 #执行探测的频率。默认是 10 秒,最小 1 秒。successThreshold: 1 #探测失败后,起码间断探测胜利多少次才被认定为胜利。默认是 1。对于 liveness 必须是 1。最小值是 1。timeoutSeconds: 5 #探测超时工夫。默认 1 秒,最小 1 秒。#Kubelet 应用 readiness probe(就绪探针)来确定容器是否曾经就绪能够承受流量。只有当 Pod 中的容器都处于就绪状态时 kubelet 才会认定该 Pod 处于就绪状态。该信号的作用是管制哪些 Pod 应该作为 service 的后端。如果 Pod 处于非就绪状态,那么它们将会被从 service 的 load balancer 中移除。readinessProbe:
            exec:
              command:
                - /bin/sh
                - "-c"
                - MYSQL_PWD="${MYSQL_ROOT_PASSWORD}"
                - mysql -h 127.0.0.1 -u root -e "SELECT 1"
            failureThreshold: 3
            initialDelaySeconds: 5
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 1

容器初始化

容器的一些初始化操作显然适宜通过 InitContainer 来实现,这里的 initContainer 是为了保障在 POD 启动前,PV 盘 要后行绑定胜利,同时为了防止 MySQL 数据库目录内的 lost+found 目录被误认为是数据库,初始化容器中将其删除;

 #Init 容器反对利用容器的全副字段和个性,包含资源限度、数据卷和平安设置。然而,Init 容器对资源申请和限度的解决稍有不同,在上面 资源 处有阐明。而且 Init 容器不反对 Readiness Probe,因为它们必须在 Pod 就绪之前运行实现。#如果为一个 Pod 指定了多个 Init 容器,那些容器会按程序一次运行一个。每个 Init 容器必须运行胜利,下一个才可能运行。当所有的 Init 容器运行实现时,Kubernetes 初始化 Pod 并像平时一样运行利用容器。#mysql 这里的 initContainer 是为了保障在 POD 启动前,PV 盘要后行绑定胜利。initContainers:
   - command:
       - rm
       - -fr
       - /var/lib/mysql/lost+found
     image: busybox:1.29.3
     imagePullPolicy: IfNotPresent
     name: remove-lost-found
     resources: {}
     terminationMessagePath: /dev/termination-log
     terminationMessagePolicy: File
     volumeMounts:
       - mountPath: /var/lib/mysql
         name: data
 restartPolicy: Always
 #scheduler 是 kubernetes 的调度器,次要的工作是把定义的 pod 调配到集群的节点上。schedulerName: default-scheduler
 securityContext: {}
 #如果您的 Pod 通常须要超过 30 秒能力敞开,请确保减少优雅终止宽限期。能够通过在 Pod YAML 中设置 terminationGracePeriodSeconds 选项来实现.
 #如果容器在优雅终止宽限期后仍在运行,则会发送 SIGKILL 信号并强制删除。与此同时,所有的 Kubernetes 对象也会被革除。terminationGracePeriodSeconds: 30
 #定义数据卷 PVC, 与 PV 匹配。volumes:
   - name: data
     persistentVolumeClaim:
       claimName: mysql-min
   - name: mysql-config
     configMap:
       name: mysql-config
   - name: localtime
     hostPath:
       type: File
       path: /etc/localtime

残缺 Deployment

通过如上多步调整,MySQL 数据库的 Deplyment 如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    deployment.kubernetes.io/revision: "1"
  generation: 1
  labels:
    app: mysql-min
    release: mysql-min
  name: mysql-min
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql-min
  strategy:
    rollingUpdate:
      maxSurge: 1 #滚动降级时会先启动 1 个 pod
      maxUnavailable: 1 #滚动降级时容许的最大 Unavailable 的 pod 个数
    type: RollingUpdate #滚动降级
  template:
    metadata:
      labels:
        app: mysql-min
    spec:
      containers:
        - env:
            #password 存储在 secret 中
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: mysql-root-password
                  name: mysql-min
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  key: mysql-password
                  name: mysql-min
            - name: MYSQL_USER
              value: apollo
          image: centos/mysql-57-centos7:latest
          imagePullPolicy: IfNotPresent
          #kubelet 应用 liveness probe(存活探针)来确定何时重启容器。例如,当应用程序处于运行状态但无奈做进一步操作,liveness 探针将捕捉到 deadlock,重启处于该状态下的容器,使应用程序在存在 bug 的状况下仍然可能持续运行上来
          livenessProbe:
            exec:
              command:
                - /bin/sh
                - "-c"
                - MYSQL_PWD="${MYSQL_ROOT_PASSWORD}"
                - mysql -h 127.0.0.1 -u root -e "SELECT 1"
            failureThreshold: 3 #探测胜利后,起码间断探测失败多少次才被认定为失败。默认是 3。最小值是 1。initialDelaySeconds: 30 #容器启动后第一次执行探测是须要期待多少秒。periodSeconds: 10 #执行探测的频率。默认是 10 秒,最小 1 秒。successThreshold: 1 #探测失败后,起码间断探测胜利多少次才被认定为胜利。默认是 1。对于 liveness 必须是 1。最小值是 1。timeoutSeconds: 5 #探测超时工夫。默认 1 秒,最小 1 秒。name: mysql-min
          ports:
            - containerPort: 3306
              name: mysql
              protocol: TCP
          #Kubelet 应用 readiness probe(就绪探针)来确定容器是否曾经就绪能够承受流量。只有当 Pod 中的容器都处于就绪状态时 kubelet 才会认定该 Pod 处于就绪状态。该信号的作用是管制哪些 Pod 应该作为 service 的后端。如果 Pod 处于非就绪状态,那么它们将会被从 service 的 load balancer 中移除。readinessProbe:
            exec:
              command:
                - /bin/sh
                - "-c"
                - MYSQL_PWD="${MYSQL_ROOT_PASSWORD}"
                - mysql -h 127.0.0.1 -u root -e "SELECT 1"
            failureThreshold: 3
            initialDelaySeconds: 5
            periodSeconds: 10
            successThreshold: 1
            timeoutSeconds: 1
          resources:
            requests:
              cpu: 100m
              memory: 256Mi
          #为了达到一个相当高水平的实用性,特地是为了踊跃开发利用,疾速调试失败是很重要的。除了个别的日志采集,Kubernetes 还能通过查出重大谬误起因来减速调试,并在某种程度上通过 kubectl 或者 UI 排列进去。能够指定一个’terminationMessagePath’来让容器写下它的“death rattle“,比方申明失败音讯,堆栈跟踪,免责条款等等。默认路径是‘/dev/termination-log’。terminationMessagePath: /dev/termination-log
          # 此字段默认为“File“,这意味着仅从终止音讯文件中检索终止音讯。通过将 terminationMessagePolicy 设置为“FallbackToLogsOnError“,你就能够通知 Kubernetes,在容器因谬误退出时,如果终止音讯文件为空,则应用容器日志输入的最初一块作为终止音讯。日志输入限度为 2048 字节或 80 行,以较小者为准。terminationMessagePolicy: File
          #要应用的数据盘目录,在 initContainer 中会关联此处目录。volumeMounts:
            - mountPath: /var/lib/mysql
              name: data
            - name: mysql-config
              mountPath: /etc/my.cnf.d/my.cnf
              subPath: my.cnf
            - name: localtime
              readOnly: true
              mountPath: /etc/localtime
      dnsPolicy: ClusterFirst
      #Init 容器反对利用容器的全副字段和个性,包含资源限度、数据卷和平安设置。然而,Init 容器对资源申请和限度的解决稍有不同,在上面 资源 处有阐明。而且 Init 容器不反对 Readiness Probe,因为它们必须在 Pod 就绪之前运行实现。#如果为一个 Pod 指定了多个 Init 容器,那些容器会按程序一次运行一个。每个 Init 容器必须运行胜利,下一个才可能运行。当所有的 Init 容器运行实现时,Kubernetes 初始化 Pod 并像平时一样运行利用容器。#mysql 这里的 initContainer 是为了保障在 POD 启动前,PV 盘要后行绑定胜利。initContainers:
        - command:
            - rm
            - -fr
            - /var/lib/mysql/lost+found
          image: busybox:1.29.3
          imagePullPolicy: IfNotPresent
          name: remove-lost-found
          resources: {}
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
            - mountPath: /var/lib/mysql
              name: data
      restartPolicy: Always
      #scheduler 是 kubernetes 的调度器,次要的工作是把定义的 pod 调配到集群的节点上。schedulerName: default-scheduler
      securityContext: {}
      #如果您的 Pod 通常须要超过 30 秒能力敞开,请确保减少优雅终止宽限期。能够通过在 Pod YAML 中设置 terminationGracePeriodSeconds 选项来实现.
      #如果容器在优雅终止宽限期后仍在运行,则会发送 SIGKILL 信号并强制删除。与此同时,所有的 Kubernetes 对象也会被革除。terminationGracePeriodSeconds: 30
      #定义数据卷 PVC, 与 PV 匹配。volumes:
        - name: data
          persistentVolumeClaim:
            claimName: mysql-min
        - name: mysql-config
          configMap:
            name: mysql-config
        - name: localtime
          hostPath:
            type: File
            path: /etc/localtime

创立此 Deployment 后,咱们有如下组件:

# kubectl get all,pvc,cm,secret -l app=mysql-min
# MySQL pod:NAME                           READY   STATUS    RESTARTS   AGE
pod/mysql-min-f9c9b7b5-q9br4   1/1     Running   6          14d

# Service:NAME                TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
service/mysql-min   NodePort   10.96.184.130   <none>        3306:30336/TCP   16d

# MySQL Deployment:NAME                        READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/mysql-min   1/1     1            1           16d

# 正本集 ReplicaSet 被 Deployment 调用,其是主动生成的
NAME                                   DESIRED   CURRENT   READY   AGE
replicaset.apps/mysql-min-587cf9fd48   0         0         0       16d
replicaset.apps/mysql-min-589bf8cdc5   0         0         0       16d
replicaset.apps/mysql-min-6b7447c7dd   0         0         0       14d
replicaset.apps/mysql-min-6cc9887459   0         0         0       16d
replicaset.apps/mysql-min-7759579d77   0         0         0       16d
replicaset.apps/mysql-min-84d4d6bd56   0         0         0       15d
replicaset.apps/mysql-min-f9c9b7b5     1         1         1       14d

# Pvc:NAME                              STATUS   VOLUME               CAPACITY   ACCESS MODES   STORAGECLASS                   AGE
persistentvolumeclaim/mysql-min   Bound    mysql-min-pv-local   5Gi       RWO            mysql-min-storageclass-local   16d

# Secret:NAME               TYPE     DATA   AGE
secret/mysql-min   Opaque   2      16d

定期主动备份

思考到数据安全性,咱们定期备份数据库,在 K8S 集群中,咱们可配置 CronJob 实现主动备份作业。首先,创立一个长久化存储供备份用:

apiVersion: v1
items:
- apiVersion: v1
  kind: PersistentVolumeClaim
  metadata:
    #当启用 PVC 爱护 alpha 性能时,如果用户删除了一个 pod 正在应用的 PVC,则该 PVC 不会被立刻删除。PVC 的删除将被推延,直到 PVC 不再被任何 pod 应用。#能够看到,当 PVC 的状态为 Teminatiing 时,PVC 受到爱护,Finalizers 列表中蕴含 kubernetes.io/pvc-protection:finalizers:
    - kubernetes.io/pvc-protection
    labels:
      app: mysql-min
      release: mysql-min
    name: mysql-min-backup
    namespace: default
  spec:
    #PV 的拜访模式(accessModes)有三种:#ReadWriteOnce(RWO):是最根本的形式,可读可写,但只反对被单个 Pod 挂载。#ReadOnlyMany(ROX):能够以只读的形式被多个 Pod 挂载。#ReadWriteMany(RWX):这种存储能够以读写的形式被多个 Pod 共享。accessModes:
    - ReadWriteOnce
    resources:
      requests:
        storage: 10Gi
    storageClassName: mysql-min-storageclass-nfs
    #示意应用本地磁盘,理论生产中个别都应用 nfs。volumeMode: Filesystem
    volumeName: mysql-min-pv-local
#  status:
#    accessModes:
#    - ReadWriteOnce
#    capacity:
#      storage: 1Gi
kind: List

继而,配置理论的自动化作业工作,如下所示,每天凌晨零点点将应用 mysqldump 备份 mall 数据库。

apiVersion: batch/v1beta1
kind: CronJob
metadata:
  name: mysql-backup
spec:
  schedule: "0 0 * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: mysql-min-backup
              imagePullPolicy: IfNotPresent
              image: centos/mysql-57-centos7:latest
              env:
                #password 存储在 secret 中
                - name: MYSQL_ROOT_PASSWORD
                  valueFrom:
                    secretKeyRef:
                      key: mysql-root-password
                      name: mysql-min
                - name: MYSQL_PASSWORD
                  valueFrom:
                    secretKeyRef:
                      key: mysql-password
                      name: mysql-min
                - name: MYSQL_HOST
                  value: mysql-min
              command:
                - /bin/sh
                - -c
                - |
                  set -ex
                  mysqldump --host=$MYSQL_HOST --user=$MYSQL_ROOT_PASSWORD \
                            --password=$mysql-root-password \
                            --routines --databases mall --single-transaction \
                            > /mysql-backup/mysql-`date +"%Y%m%d"`.sql
              volumeMounts:
                - name: mysql-min-backup
                  mountPath: /mysql-min-backup
          restartPolicy: OnFailure
          volumes:
            - name: mysql-min-backup
              persistentVolumeClaim:
                claimName: mysql-min-backup

小结

​Kubernetes 很多看起来比拟“繁琐”的设计的次要目标,都是心愿为开发者提供更多的“可扩展性”,给使用者带来更多的“稳定性”和“安全感”。这两个能力的高下,是掂量开源基础设施我的项目程度的重要规范。示例中揉合 Kubernetes 多项技术,构建了一个简单且可做生产应用的单实例数据库。

本文源码:https://github.com/zuozewei/b…

参考资料:

[1]:《深刻分析 Kubernetes》

点击关注,第一工夫理解华为云陈腐技术~

正文完
 0