写在最前
根据你自身的需求选择任意一种部署方式,如果是新人可以先看之前的篇章来完成基础环境的安装与配置。
1. 前置要求
2. docker 部署
mkdir -p /data/mysql8/conf /data/mysql8/data
docker run -d \
--privileged=true \
--name mysql8 \
--restart=always \
-p 3306:3306 \
-v /data/mysql8/conf:/etc/mysql/conf.d \
-v /data/mysql8/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_DATABASE=test-db \
mysql:8.0.20 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_bin
2.3 备份与还原
2.3.1 只读账号
创建只读的账号来进行操作,禁止远程连接,禁止弱密码,禁止使用root账号。
推荐使用在线随机密码生成器或者uuid作为密码都是不错的选择。
-- 创建新用户,替换 'backup_user' 和 'your_password' 为你想要的用户名和密码
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY '实际密码';
-- 给用户赋予所有数据库的只读权限
GRANT SELECT ON *.* TO 'backup_user'@'localhost';
-- 刷新权限
FLUSH PRIVILEGES;
3.2.2 备份脚本
原理是执行 docker exec 获取所有的库名再循环它使用 docker exec 导出该库的所有数据得到sql文件再打包出去。
每次执行判断将该目录下的超过xx天后的目录给删除掉。只保留xx天的数据。
所有的日志都拼接在 LOG_OUTPUT 变量里,后续可以拓展将此变量的内容通过邮件发送出去,每天都能看到可控的信息。
#!/bin/bash
# MySQL 容器名称
CONTAINER_NAME="mysql8"
# 备份用户和密码
MYSQL_USER="backup_user"
MYSQL_PASSWORD="实际密码"
# 保留的天数,例如保留 7 天
RETENTION_DAYS=7
# 初始化日志变量
LOG_OUTPUT=""
# 获取当前日期并创建对应的文件夹,日期格式为 "2024-09-20"
DATE=$(date +"%Y-%m-%d")
BACKUP_DIR="/backup/mysql/$DATE"
mkdir -p "$BACKUP_DIR"
# 记录备份开始
LOG_OUTPUT+="备份开始...\n"
# 获取所有数据库名
DATABASES=$(docker exec "$CONTAINER_NAME" sh -c "exec mysql -u$MYSQL_USER -p$MYSQL_PASSWORD -e 'SHOW DATABASES;'" | grep -Ev "(Database|information_schema|performance_schema|mysql|sys)")
# 循环导出每个数据库并打包为 .tar.gz
for DB in $DATABASES; do
# 导出数据库为 SQL 文件
docker exec "$CONTAINER_NAME" sh -c "exec mysqldump --single-transaction -u$MYSQL_USER -p$MYSQL_PASSWORD $DB" > "$BACKUP_DIR/$DB.sql"
# 记录导出日志
# LOG_OUTPUT+="数据库 $DB 已导出为 $DB.sql。\n"
# 将 SQL 文件压缩为 .tar.gz
tar -czf "$BACKUP_DIR/$DB.tar.gz" -C "$BACKUP_DIR" "$DB.sql"
# 记录压缩日志
LOG_OUTPUT+="数据库 $DB 已压缩为 $DB.tar.gz。\n"
# 删除原始的 SQL 文件
rm "$BACKUP_DIR/$DB.sql"
done
# 记录备份完成
LOG_OUTPUT+="备份完成,存储在 $BACKUP_DIR 中。\n"
# 获取当前日期的时间戳
CURRENT_TIMESTAMP=$(date +%s)
# 记录删除日志
DELETE_LOG=""
# 查找超过保留天数的备份目录并进行删除
for DIR in /backup/mysql/*; do
# 从目录名称中提取日期
BACKUP_DATE=$(basename "$DIR")
# 将目录名称的日期转换为时间戳
BACKUP_TIMESTAMP=$(date -d "$BACKUP_DATE" +%s 2>/dev/null)
# 检查日期格式是否正确(无效日期会被忽略)
if [ -n "$BACKUP_TIMESTAMP" ]; then
# 计算日期差
DIFF_DAYS=$(( (CURRENT_TIMESTAMP - BACKUP_TIMESTAMP) / (60*60*24) ))
# 如果超过保留天数,进行删除并记录删除日志
if [ "$DIFF_DAYS" -gt "$RETENTION_DAYS" ]; then
DELETE_LOG+="删除目录: $DIR (超过 $DIFF_DAYS 天)\n"
rm -rf "$DIR"
fi
fi
done
# 如果有删除操作,记录删除日志
if [ -n "$DELETE_LOG" ]; then
LOG_OUTPUT+="以下目录已被删除:\n$DELETE_LOG"
else
LOG_OUTPUT+="没有超过 $RETENTION_DAYS 天的备份被删除。\n"
fi
# 最终输出所有日志
echo -e "$LOG_OUTPUT"
3.2.3 还原脚本
3. Kubernetes 部署
namespace 我统一设置为 basic ,自行修改存储类相关配置
3.1 secret
MYSQL_ROOT_PASSWORD 值是123456
apiVersion: v1
kind: Secret
metadata:
namespace: basic
labels: {}
name: mysql-secret
type: Opaque
spec:
template:
metadata:
labels: {}
data:
MYSQL_ROOT_PASSWORD: MTIzNDU2
3.2 configmap
修改全局字符集
kind: ConfigMap
apiVersion: v1
metadata:
name: mysql8-conf
namespace: basic
annotations:
kubesphere.io/creator: admin
data:
my.cnf: |
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
[mysqld]
init_connect='SET collation_connection = utf8mb4_bin'
init_connect='SET NAMES utf8mb4'
character_set_server = utf8mb4
collation_server = utf8mb4_bin
skip-character-set-client-handshake
skip-name-resolve
3.3 deployment
kind: Deployment
apiVersion: apps/v1
metadata:
name: mysql8
namespace: basic
labels:
app: mysql8
annotations:
deployment.kubernetes.io/revision: '6'
kubesphere.io/creator: admin
spec:
replicas: 1
selector:
matchLabels:
app: mysql8
template:
metadata:
creationTimestamp: null
labels:
app: mysql8
annotations:
kubesphere.io/creator: admin
kubesphere.io/imagepullsecrets: '{}'
kubesphere.io/restartedAt: '2024-09-18T07:33:09.888Z'
logging.kubesphere.io/logsidecar-config: '{}'
spec:
volumes:
- name: host-time
hostPath:
path: /etc/localtime
type: ''
- name: mysql8-data
persistentVolumeClaim:
claimName: mysql8-data
- name: mysql8-conf
configMap:
name: mysql8-conf
defaultMode: 420
containers:
- name: container-6m2r7f
image: 'mysql:8.0.20'
ports:
- name: http-3306
containerPort: 3306
protocol: TCP
- name: http-33060
containerPort: 33060
protocol: TCP
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: MYSQL_ROOT_PASSWORD
resources: {}
volumeMounts:
- name: host-time
readOnly: true
mountPath: /etc/localtime
- name: mysql8-data
mountPath: /var/lib/mysql
- name: mysql8-conf
readOnly: true
mountPath: /etc/mysql/conf.d
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
imagePullPolicy: IfNotPresent
restartPolicy: Always
terminationGracePeriodSeconds: 30
dnsPolicy: ClusterFirst
serviceAccountName: default
serviceAccount: default
securityContext: {}
schedulerName: default-scheduler
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25%
maxSurge: 25%
revisionHistoryLimit: 10
progressDeadlineSeconds: 600
3.4 service
使用nodeport方式连接
kind: Service
apiVersion: v1
metadata:
name: mysql8
namespace: basic
labels:
app: mysql8
annotations:
kubesphere.io/creator: admin
spec:
ports:
- name: http-3306
protocol: TCP
port: 3306
targetPort: 3306
nodePort: 31205
selector:
app: mysql8
type: NodePort
sessionAffinity: None
externalTrafficPolicy: Cluster
ipFamilies:
- IPv4
ipFamilyPolicy: SingleStack
internalTrafficPolicy: Cluster
3.5 备份与还原
3.5.1 只读账号
3.5.2 备份脚本
3.5.3 还原脚本
4. 异常处理
4.1 错误1
如果出现 --initialize specified but the data directory has files in it. Aborting. 异常,请尝试加上 --privileged=true 以超级权限运行。
2.2 错误2
最新的MySQL模块并未完全支持MySQL 8.0的caching_sha2_password加密方式,而MySQL 8.0中默认仍然是caching_sha2_password加密方式,因此用户认证不通过了。
这算问题也可以不算问题,在最新的navicat17版本中是能够正常连接的。
注意,我是为了个人开发便捷将root设置为允许远程连接,生产禁止此操作。
# 1. 进入容器
docker exec -it mysql8 /bin/bash
# 2. 登录mysql
mysql -u root -p
# 3. 更新root密码规则为 mysql_native_password ,允许root远程连接,并且设密码为123456
alter user 'root'@'%' identified with mysql_native_password by '123456';
# 4. 刷新权限
flush privileges;
5. 操作总结
部署5.x很简单,但是为啥部署8.x会那么复杂多坑,可能是他的镜像做的有问题吧启动起来还不能直接使用晕死了。