企业运维 | MySQL关系型数据库在Docker与Kubernetes容器环境中快速搭建部署主从实践

2022-10-01 09:49:41 浏览数 (1)

本章目录

1.Docker 快速部署 MySQL 数据库服务器

命令方式

配置清单

2.Kubernetes 快速部署 MySQL 数据库服务器

单实例模式

主从同步模式

首发地址: https://mp.weixin.qq.com/s/7mmIsd83QPT65QnQd5CtFQ

温馨提示:唯一极客技术博客文章在线浏览【极客全栈修炼】小程序上线了,涉及网络安全、系统运维、应用开发、物联网实战、全栈文章,希望和大家一起学习进步,欢迎浏览交流!(希望大家多多提提意见)

1.Docker 快速部署 MySQL 数据库服务器

MySQL 是一种广泛使用的开源关系数据库管理系统 (RDBMS),其久经考验的性能、可靠性和易用性,MySQL 已成为基于 Web 的应用程序的领先数据库选择。

MySQL 帮助文档:https://docs.oracle.com/en-us/iaas/mysql-database/doc/getting-started.html

镜像仓库地址:https://hub.docker.com/_/mysql

镜像问题:https://github.com/docker-library/mysql/issues

温馨提示:此处实践环境是使用Docker,若你没有安装Docker环境或者不了解的Docker容器的朋友,可以参考博主学习【Docker的系列笔记】汇总:

https://blog.weiyigeek.top/2018/1-1-1.html#Docker容器学习之路汇总

命令方式

步骤 01.快速部署脚本命令。

代码语言:shell复制
# 准备数据持久化目录
mkdir -vp /app/data

# 准备mysql8.x仓库镜像
docker pull mysql:8.0.30

# 准备root密码不采用环境变量直接显示密码
echo "weiyigeek.top" > /app/my-secret-pw

# 一条命令创建运行mysql数据库容器
docker run -d --name mysql8.0 --restart=always 
-v "/app/data":/var/lib/mysql 
-v "/app/my-secret-pw":/app/my-secret-pw 
-e MYSQL_ROOT_PASSWORD_FILE=/app/my-secret-pw 
-e MYSQL_DATABASE=app 
-e MYSQL_USER=weiyigeek 
-e MYSQL_PASSWORD=password 
-p 3306:3306 
mysql:8.0.30 
--default-authentication-plugin=mysql_native_password
# 144e883af1a99901913a986d540382c8aefe3e5bd96730ad76a019b2567159bb

# 可以为 mysqld 使用特定的 UID/GID , 例如此处的 1000 用户。
--user 1000:1000 

# 可以为 mysqld 指定命令行参数。
--character-set-server=utf8mb4 
--collation-server=utf8mb4_unicode_ci

步骤 02.查看验证在Docker中的部署情况。

代码语言:shell复制
# 容器
$ docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS                               NAMES
05c5a0e23e39   mysql:8.0.30   "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:3306->3306/tcp, 33060/tcp   mysql8.0

# 日志
$ docker logs mysql8.0
2022-09-27 14:19:03 00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.30-1.el8 started.
2022-09-27 14:19:03 00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2022-09-27 14:19:03 00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 8.0.30-1.el8 started.
2022-09-27 14:19:03 00:00 [Note] [Entrypoint]: Initializing database files

# 连接测试
$ docker exec -it mysql8.0 sh -c 'mysql -u root -p"weiyigeek.top"'
mysql: [Warning] Using a password on the command line interface can be insecure.
mysql> select @@version;
 ----------- 
| @@version |
 ----------- 
| 8.0.30    |
 ----------- 
1 row in set (0.00 sec)

步骤 03.部署 Adminer 进行管理连接 MySQL 数据库, Adminer 是一个类似于 phpMyAdmin 的 MySQL 管理客户端。

Adminer 可用于连接 MySQL, PostgreSQL, SQLite, MSSQL, Oracle, Firebird, SimpleDB, Elasticsearch and MongoDB 等数据库。

代码语言:shell复制
docker pull adminer:latest

# Standalone
docker run -d --restart unless-stopped --name db_adminer -p 8080:8080 adminer:latest

# FastCGI
docker run -d --name db_admine_fastcgi --link some_database:db -p 9000:9000 adminer:fastcgi

随后使用浏览器访问宿主机的8080端口进行连接:

WeiyiGeek.db_adminerWeiyiGeek.db_adminer

温馨提示:MySQL的默认配置可以在 /etc/mysql/my.cnf,或可以自定义配置文件/etc/mysql/conf.d/my.cnf

代码语言:shell复制
tee my.cnf <<'EOF'
[mysqld]
# 执行用户
user=mysql

# 开放监听服务端口
port=3306
bind-address=*
socket=/var/run/mysqld/mysqld.sock

# 数据目录
datadir=/var/lib/mysql

# 进程 pid 文件
pid-file=/var/run/mysqld/mysqld.pid

# 插件默认路径
plugin-dir=/usr/lib64/mysql/plugin/

# 安全文件路径
secure-file-priv=/var/lib/mysql-files

# 启用日志与路径设置
general-log=on
general-log-file=/var/lib/mysql/mysql8x.log

# 服务器字符集设置
character-set-server=utf8mb4 
collation-server=utf8mb4_unicode_ci

# 数据库容灾binlog启用配置
log-bin=binlog
log-bin-index=binlog.index

# 认证密码策略, 默认 aching_sha2_password , 针对于old链接认证方式为 mysql_native_password
default-authentication-plugin=mysql_native_password

# 跳过某些操作
skip-host-cache
skip-name-resolve

[client]
socket=/var/run/mysqld/mysqld.sock
EOF

温馨提示:如果您想查看 mysqld 可用选项的完整列表,只需运行

$ docker run -it --rm mysql:8.0.30 --verbose --help

代码语言:shell复制
# my.cnf 可用配置
Variables (--variable-name=value)
and boolean options {FALSE|TRUE}                             Value (after reading options)
------------------------------------------------------------ -------------
abort-slave-event-count                                      0
activate-all-roles-on-login                                  FALSE
...................................
wait-timeout                                                 28800
windowing-use-high-precision                                 TRUE
xa-detach-on-prepare                                         TRUE

默认支持环境变量

代码语言:shell复制
MYSQL_DATABASE=数据库名称
MYSQL_USER=应用用户
MYSQL_PASSWORD=应用账号密码
MYSQL_ROOT_PASSWORD=ROOT账户密码
MYSQL_RANDOM_ROOT_PASSWORD=yes # 允许为为 root 用户生成一个随机初始密码并将其打印到stdout
MYSQL_ALLOW_EMPTY_PASSWORD=yes # 以允许使用根用户的空白密码启动容器,非常不建议在实践环境中使用该变量
# MYSQL_ONETIME_PASSWORD   # 通常不适用,此功能仅在 MySQL 5.6  上受支持。 在 MySQL 5.5 上使用此选项将在初始化期间引发适当的错误。 
# MYSQL_INITDB_SKIP_TZINFO # 默认情况下,入口点脚本会自动加载所需的时区数据 CONVERT_TZ()功能。 如果不需要,任何非空值都会禁用时区加载。 

温馨提示: 为了替代环境变量传递敏感信息 , 我们可在 MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql-root, 可在如下变量中添加 _FILE= 目前仅支持 ,MYSQL_ROOT_PASSWORD, MYSQL_ROOT_HOST, MYSQL_DATABASE, MYSQL_USER 和 MYSQL_PASSWORD

数据库备份、恢复

代码语言:shell复制
# 备份
$ docker exec mysql8.0 sh -c 'exec mysqldump --all-databases -uroot -p"$MYSQL_ROOT_PASSWORD"' > /some/path/on/your/host/all-databases.sql

# 恢复
$ docker exec -i mysql8.0 sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD"' < /some/path/on/your/host/all-databases.sql

配置清单

描述:我们可以使用类似于配置清单文件,使用 docker 的 stack 子命令或者 docker-compose 名来部署 stack.yml

步骤 01.准备 mysql.yaml 部署清单

代码语言:yaml复制
version: '3.1'
services:
  db:
    image: mysql:8.0.30
    container_name: mysql8.x
    # NOTE: use of "mysql_native_password" is not recommended: https://dev.mysql.com/doc/refman/8.0/en/upgrading-from-previous-series.html#upgrade-caching-sha2-password
    # (this is just an example, not intended to be a production configuration)
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    environment:
      # MYSQL_ROOT_PASSWORD: example
      MYSQL_ROOT_PASSWORD_FILE: /app/my-secret-pw
      MYSQL_DATABASE: app
      MYSQL_USER: weiyigeek
      MYSQL_PASSWORD: password
    volumes:
      - "/app/data:/var/lib/mysql"
      - "/app/my-secret-pw:/app/my-secret-pw"
    ports:
      - 3306:3306
  # 部署adminer 进行图形化管理 mysql 数据库
  adminer:
    image: adminer
    restart: always
    ports:
      - 8080:8080

步骤 02.准备本地持久化数据库以及root认证密码

代码语言:shell复制
mkdir -vp /app/data
echo "weiyigeek.top" > /app/my-secret-pw

步骤 03.使用docker或者docker-compose进行部署

代码语言:shell复制
docker stack deploy -c mysql.yml mysql 
docker-compose -f mysql.yml up

2.Kubernetes 快速部署 MySQL 数据库服务器

当前,许多企业开始构建自己的容器化架构,而 mysql 部署在 k8s 上的优势主要有以下几点:

  • 资源隔离
  • 动态弹性扩缩容
  • 环境一致性
  • 运维方便

温馨提示:此处实践环境是使用Kubernetes集群,若你没有安装Kubernetes集群环境或者不了解的Kubernetes的朋友,可以参考博主学习【Kubernetes的系列笔记】汇总:

https://blog.weiyigeek.top/2018/1-1-1.html#Kubernetes学习之路汇总

单实例模式

步骤 01.准备mysql部署资源清单,此处使用StatefulSet与Service资源清单。

代码语言:yaml复制
tee K8s-Standalone-MySQL.yaml <<'EOF'
kind: Service
apiVersion: v1
metadata:
  name: {APP_NAME}
  namespace: {NAMESPACE}
  labels:
    app: {APP_NAME}
    type: standalone
spec:
  type: NodePort
  ports:
  - name: server
    port: 3306
    protocol: TCP
    targetPort: 3306
    nodePort: {NODEPORT}
  selector:
    app: {APP_NAME}
    type: standalone
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {APP_NAME}
  namespace: {NAMESPACE}
  labels:
    app: {APP_NAME}
    type: standalone
  annotations:
    version: {APP_VERSION}
spec:
  replicas: 1
  selector:
    matchLabels:
      app: {APP_NAME}
      type: standalone
  serviceName: {APP_NAME}
  template:
    metadata:
      labels:
        app: {APP_NAME}
        type: standalone
    spec:
      # 运行节点标签选择
      # nodeSelector:
      #   app: database
      containers:
      - name: {APP_NAME}
        image: mysql:{APP_VERSION}
        imagePullPolicy: IfNotPresent
        ports:
        - name: server
          containerPort: 3306
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "{MYSQL_ROOT_PASSWORD}"
        - name: MYSQL_DATABASE
          value: "{MYSQL_DATABASE}"
        - name: MYSQL_USER
          value: "{MYSQL_USER}"
        - name: MYSQL_PASSWORD
          value: "{MYSQL_PASSWORD}"
        volumeMounts:
        - name: data
          mountPath: /var/lib/mysql
      #  - name: mysql-conf
      #    mountPath: /etc/mysql/my.cnf
      #    subPath: my.cnf
      #  - name: log
      #    mountPath: /var/log/mysqld.log
        resources:
          limits:
            memory: "4Gi"
            cpu: "2"
          requests:
            memory: "512Mi"
            cpu: "1"
      volumes:
      # 方式1,持久化 hostPath
      - name: mysql-persistent-storage
        hostPath:
          path: {HOSTPATH}
          type: DirectoryOrCreate
      # - name: mysql-conf
      #   configMap:
      #     name: mysql-conf
      #     items:
      #     - key: my.cnf
      #       path: my.cnf
   # 方式2,持久化nfs存储卷
  volumeClaimTemplates:
  - metadata:
      name: data
      labels:
        app: {APP_NAME}
        type: standalone
    spec:
      accessModes:
      - ReadWriteOnce
      storageClassName: {storageClassName}
      resources:
        requests:
          storage: 5Gi
EOF

步骤 02.准备持久化目录与替换部署清单关键字。

代码语言:shell复制
# 注意,通常此目录为挂到各k8s节点上的nfs服务存储
mkdir -vp /app/data

# 替换关键配置
sed -i -e "s#{APP_NAME}#mysql-weiyigeek#g" -e "s#{NAMESPACE}#database#g" -e "s#{NODEPORT}#31001#g"  -e "s#{APP_VERSION}#8.0.30#g" 
-e "s#{MYSQL_ROOT_PASSWORD}#weiyigeek.top#g"  -e "s#{MYSQL_DATABASE}#app#g" -e "s#{MYSQL_USER}#weiyigeek#g"  -e "s#{MYSQL_PASSWORD}#password#g" 
-e "s#{HOSTPATH}#/app/data#g" -e "s#{storageClassName}#nfs-dev#g" 
K8s-Standalone-MySQL.yaml

# 例如,可以将 my.cnf 使用 configmap 控制器进行存储,此外我采用镜像缺省的没有使用如下方式。
kubectl create configmap mysql-conf --from-file=my.cnf --namespace database

步骤 03.在K8S中执行部署mysql的命令

代码语言:shell复制
# 名词空间
kubectl create namespace database

# 部署mysql资源清单
kubectl apply -f K8s-Standalone-MySQL.yaml
  # service/mysql-weiyigeek created
  # statefulset.apps/mysql-weiyigeek created
  
# 查看部署情况
kubectl get sts,svc,pod -n database
  # NAME                         READY   AGE
  # statefulset.apps/mysql-weiyigeek   1/1     77s
  
  # NAME                TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
  # service/mysql-weiyigeek   NodePort   10.108.74.113    <none>        3306:31001/TCP   77s
  
  # NAME              READY   STATUS    RESTARTS   AGE
  # pod/mysql-weiyigeek-0   1/1     Running   0          77s

# 日志查看
kubectl logs -f --tail 50 -n database pod/mysql-weiyigeek-0

# 持久化数据查看
kubectl get pvc -n database
  # NAME               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
  # data-mysql-weiyigeek-0   Bound    pvc-37390e64-9401-4b66-8b4f-216d91e2a7fd   5Gi        RWO            nfs-dev        4m55s

cd /storage/dev/pvc/local/database-data-mysql-weiyigeek-0-pvc-37390e64-9401-4b66-8b4f-216d91e2a7fd
ls 
  # app             binlog.000002   ca.pem           '#ib_16384_0.dblwr'   ibdata1        '#innodb_temp'   mysql.sock           public_key.pem    sys
  # auto.cnf        binlog.index    client-cert.pem  '#ib_16384_1.dblwr'   ibtmp1          mysql           performance_schema   server-cert.pem   undo_001
  # binlog.000001   ca-key.pem      client-key.pem    ib_buffer_pool      '#innodb_redo'   mysql.ibd       private_key.pem      server-key.pem    undo_002

步骤 04.使用 adminer 连接 k8s 部署的 MySQL 数据库,验证其服务。

主从同步模式

此节,我们实践在K8S集群中搭建一个 MySQL 主从数据库,主(可读、可写),从只读,如下是MySQL主从原理图以及MySQL主从模式在K8S集群中的部署架构。

步骤 01.添加 helm 源并在源中下载 mysql 部署清单到本地,此处我的helm版本为v3.9.0。

代码语言:shell复制
# 温馨提示:master节点上需要安装 helm 然后进行拉取部署的相关资源部署清单图表
helm3 repo add bitnami https://charts.bitnami.com/bitnami
helm3 search repo bitnami/mysql -l
  # NAME            CHART VERSION   APP VERSION     DESCRIPTION
  # bitnami/mysql   9.3.4           8.0.30          MySQL is a fast, reliable, scalable, and easy t....

# 拉取到本地以及其部署清单图表
$ helm3 pull bitnami/mysql  --version 9.3.4 --untar
$ ls mysql/
Chart.lock  charts  Chart.yaml  README.md  templates  values.schema.json  values.yaml

步骤 02.修改该 Chart 图表 values.yaml 文件,已下逻辑出主要修改点。

代码语言:shell复制
vim mysql/values.yaml
....
# 修改1.使用内部仓库镜像地址(后续会将其同步到内部harbor中此处先更改)
image:
  registry: harbor.weiyigeek.top
  repository: library/mysql
  tag: 8.0.30-debian-11-r15
...
# 修改2.MySQL部署模式 (`standalone` or `replication`)此处为主从复制。
architecture: replication

# 修改3.数据库认证账号(root、普通用户、replication用户)相关密码以及创建的数据库设置,密码留空则会自动生成
auth:
  rootPassword: ""
  createDatabase: true
  database: "app"
  username: "app"
  password: ""
  replicationUser: replicator
  replicationPassword: ""

# 修改4.MySQL Primary 服务相关参数配置
primary:
  name: primary
  # 资源限制 : 此处 1000m 表示使用1个CPU的资源,内存最大4G。
  resources:
    limits:
      cpu: 1000m   
      memory: 4Gi
  # 修改5.主资源持久化配置,此处我已经搭建了动态逻辑卷。
  persistence:
    enabled: true
    storageClass: "nfs-local"
    accessModes:
      - ReadWriteOnce
    size: 10Gi
  # 修改6.主服务持久化配置,注意此处与secondary服务节点配置不同
  service:
    type: NodePort
    ports:
      mysql: 3306
    nodePorts:
      mysql: "31006"

# 修改7.MySQL Secondary 服务相关参数配置
secondary:
  name: secondary
  replicaCount: 2
  resources:
  limits:
    cpu: 1000m
    memory: 2048Mi
  # 修改6.从(节点)资源持久化配置,此处我已经搭建了动态逻辑卷。
  persistence:
    enabled: true
    storageClass: "nfs-local"
    accessModes:
      - ReadWriteOnce
    size: 10Gi
  # 修改8.从(节点)持久化配置,注意此处与primary服务节点配置不同
  service:
    type: NodePort
    ports:
      mysql: 3306
    nodePorts:
      mysql: "31008"

# 修改点9.启用 Promethues 的 mysqld-exporter
metrics:
  enabled: true
  image:
    registry: harbor.weiyigeek.top
    repository: library/mysqld-exporter
    tag: 0.14.0-debian-11-r33

步骤 03.为了加快拉取速度,此处将镜像拉取上传到内部harbor中

代码语言:shell复制
docker pull bitnami/mysqld-exporter:0.14.0-debian-11-r33
docker tag bitnami/mysqld-exporter:0.14.0-debian-11-r33 harbor.weiyigeek.top/library/mysqld-exporter:0.14.0-debian-11-r33
docker push harbor.weiyigeek.top/library/mysqld-exporter:0.14.0-debian-11-r33

docker pull bitnami/mysql:8.0.30-debian-11-r15
docker tag bitnami/mysql:8.0.30-debian-11-r15 harbor.weiyigeek.top/library/mysql:8.0.30-debian-11-r15
docker push harbor.weiyigeek.top/library/mysql:8.0.30-debian-11-r15

步骤 04.使用helm3安装我们修改后的MySQL主从图表,以及显示安装情况

代码语言:shell复制
$ helm3 install mysql ./mysql --namespace database --create-namespace
  # NAME: mysql
  # LAST DEPLOYED: Wed Sep 28 16:33:23 2022
  # NAMESPACE: database
  # STATUS: deployed
  # REVISION: 1
  # TEST SUITE: None
  # NOTES:
  # CHART NAME: mysql
  # CHART VERSION: 9.3.4
  # APP VERSION: 8.0.30

$ helm3 list -n database
  # NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
  # mysql   database        1               2022-09-28 16:33:23.01465975  0800 CST  deployed        mysql-9.3.4     8.0.30

$ kubectl get sts,pod -n database -l app.kubernetes.io/name=mysql
  # NAME                               READY   AGE
  # statefulset.apps/mysql-primary     1/1     2m37s
  # statefulset.apps/mysql-secondary   2/2     2m37s
  
  # NAME                    READY   STATUS    RESTARTS   AGE
  # pod/mysql-primary-0     2/2     Running   0          2m37s
  # pod/mysql-secondary-0   2/2     Running   0          2m37s
  # pod/mysql-secondary-1   2/2     Running   0          95s

步骤 05.获取自动生成的MySQL root、app以及replication用户密码

代码语言:shell复制
echo -n "MYSQL_ROOT_PASSWORD=";kubectl get secret --namespace database mysql -o jsonpath="{.data.mysql-root-password}" | base64 -d;echo
# MYSQL_ROOT_PASSWORD=oX7112Avng

echo -n "MYSQL_PASSWORD=";kubectl get secret --namespace database mysql -o jsonpath="{.data.mysql-password}" | base64 -d;echo
# MYSQL_PASSWORD=pdtsixSpV28

echo -n "MYSQL_REPLICATION_PASSWORD=";kubectl get secret --namespace database mysql -o jsonpath="{.data.mysql-replication-password}" | base64 -d;echo
# MYSQL_REPLICATION_PASSWORD=FJRspMupePE

步骤 06.使用 Adminer 连接到主服务中进行读写,然后验证从节点的是否正确可读。

主节点服务中创建表并插入数据

代码语言:sql复制
-- To connect to primary service (read/write):
CREATE TABLE replication (
  id int(11) NOT NULL  PRIMARY KEY AUTO_INCREMENT,
  name VARCHAR(255)  NOT NULL,
  INDEX name_in (name)
);
INSERT INTO app.replication(name) VALUES('WeiyiGeek')

-- 创建数据库、用户、并将创建的数据库所有权赋予给创建用户
CREATE DATABASE dev;
CREATE USER 'dev'@'%' IDENTIFIED BY 'dev.weiyigeek.top';  
GRANT ALL ON dev.* TO 'dev'@"%";
FLUSH PRIVILEGES;

从节点查询插入的数据

代码语言:sql复制
-- To connect to secondary service (read):
kubectl run mysql-client --rm --tty -i --restart='Never' --image  harbor.weiyigeek.top/library/mysql:8.0.30-debian-11-r15 --namespace database --env MYSQL_ROOT_PASSWORD=oX7xxIovng --command -- bash
--# mysql -h mysql-primary.database.svc -u app -p"$MYSQL_PASSWORD"
mysql -h mysql-secondary.database.svc -u app -p"$MYSQL_PASSWORD"

步骤 07.查看exporter监控数据, 此处就不演示在Grafana在集群中MySQL资源监控, 如果想卸载安装的MySQL主从。

基于 mysqld-exporter 的 Grafana 模板 :https://grafana.com/grafana/dashboards/7362

代码语言:shell复制
# 通过命令查看采集数据.
kubectl get --raw http://10.66.35.76:9104/metrics
kubectl get --raw http://10.66.53.95:9104/metrics

# 通过helm3卸载安装的mysql主从.
helm3 uninstall mysql --namespace database
# kubectl delete pod -n database `kubectl get pod -n database | awk 'NR>1{print $1}'` --force

# 删除创建的名称空间, 注意删除名词空间时, 若有其他资源请谨慎执行如下命令。
kubectl patch ns database -p '{"metadata":{"finalizers":null}}'
kubectl delete ns database --force

至此,在容器化环境中安装MySQL主从实践完毕。

原文地址: https://blog.weiyigeek.top/2022/3-24-687.html

本文至此完毕,更多技术文章,尽情期待下一章节!

0 人点赞