第3章 云原生应用实战-Kubernetes部署MySql主从
作者:王珂
邮箱:49186456@qq.com
前言
本节课程主要给大家讲解如何在Kubernetes中搭建一个MySql主从集群。在Kubernetes中部署一个应用我们通常会定义一个Yaml文件,然后将所有声明式API都写在这个Yaml中。但是这样会导致我们的Yaml文件特别庞大,不好维护。当然,我们也可以把不同的资源对象写在单独的Yaml文件中,这种方式有没有对应的规范约束呢?答案是Helm,我就会采用这种方式,具体详见正文。
一、部署MySql主从
1.1 Helm方式部署
我们通过自定helm方式部署MySql主从集群。
- mysql-ms目录结构
首先,我们创建一个文件目录叫做mysql-ms-8.0.21(8.0.21表示我们用的MySql版本为8.0.21),其中的文件结构如下:
mysql-ms-8.0.21
│ Chart.yaml
│ values.yaml
│
├─charts
└─templates
configmap.yaml
namespace.yaml
secret.yaml
service.yaml
statefulset.yaml
- 自定义helm文件
- Chart.yaml
apiVersion: v2
name: mysql-ms
description: A Helm chart for MySql Master Slave Cluster
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
version: 1.0.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application.
appVersion: 8.0.21
- values.yaml
# Default values for mysql-ms.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: mysql:8.0.21
pullPolicy: IfNotPresent
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name:
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: NodePort
port: 30081
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
nodeSelector: {}
tolerations: []
affinity: {}
- namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: ns-mysql
- configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-mysql-ms
namespace: ns-mysql
data:
master.cnf: |
[client]
default-character-set=utf8mb4
# Master配置
[mysqld]
character-set-server=utf8mb4
lower-case-table-names=1
skip-name-resolve
log-bin=master-bin
slave.cnf: |
[client]
default-character-set=utf8mb4
# Slave配置
[mysqld]
character-set-server=utf8mb4
lower-case-table-names=1
skip-name-resolve
log-bin=slave-bin
#super-read-only
#replicate-ignore-db=mysql
- secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
namespace: ns-mysql
type: Opaque
data:
password: MTIzNDU2 # 123456
# 主从账号
replicationUser: cmVwbA== # repl
replicationPassword: MTIzNDU2 # 123456
- statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: sts-mysql-ms
namespace: ns-mysql
spec:
serviceName: svc-mysql-read
selector:
matchLabels:
app: mysql
replicas: 2
template:
metadata:
labels:
app: mysql
spec:
# 初始化容器
initContainers:
- name: init-mysql
image: mysql:8.0.21
command:
- bash
- "-c"
- |
set -ex
# 从pod名称的序号生成server-id
ordinal=`hostname | awk -F "-" '{print $4}'` || exit 1
echo [mysqld] > /etc/mysql/conf.d/server-id.cnf
# 因为server-id不能为0,因此给它加上了100
echo server-id=$((100 + $ordinal)) >> /etc/mysql/conf.d/server-id.cnf
# 如果ordinal序号为0,说明它是master节点,从configmap里把master节点的配置信息复制到/etc/mysql/conf.d/目录下
if [ $ordinal -eq 0 ]; then
cp /mnt/config-map/master.cnf /etc/mysql/conf.d
else
cp /mnt/config-map/slave.cnf /etc/mysql/conf.d
fi
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
- name: MYSQL_REPLICATION_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: replicationUser
- name: MYSQL_REPLICATION_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: replicationPassword
volumeMounts:
#- name: timezone
# mountPath: /etc/localtime
- name: conf
mountPath: /etc/mysql/conf.d
- name: config-map
mountPath: /mnt/config-map
# 主容器
containers:
- name: mysql
image: mysql:8.0.21
ports:
- name: mysql-port
containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password
- name: MYSQL_REPLICATION_USER
valueFrom:
secretKeyRef:
name: mysql-secret
key: replicationUser
- name: MYSQL_REPLICATION_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: replicationPassword
volumeMounts:
#- name: timezone
# mountPath: /etc/localtime
- name: data
mountPath: /var/lib/mysql
- name: conf
mountPath: /etc/mysql/conf.d
- name: init-sql
mountPath: /var/run/mysql
resources:
requests:
cpu: 500m
lifecycle:
postStart:
exec:
command:
- bash
- "-c"
- |
set -ex
cd /var/lib/mysql
# 检查是否存在MySqlInitCompleted文件,如果不存在则进行初始化
if [ ! -f mysqlInitLock ]; then
# 执行一条mysql命令,查看mysql是否准备就绪,如果没有就反复执行直到可以运行MySql命令
until mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "use mysql;select 1;"; do sleep 1; done
echo "MySql已经就绪"
# 判断是master还是slave
pod_seq=`hostname | awk -F "-" '{print $4}'`
if [ $pod_seq -eq 0 ]; then
# 当前为主节点
# 授予root可以远程登录
#mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "create user 'root'@'%' identified with mysql_native_password by '${MYSQL_ROOT_PASSWORD}';"
#mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "grant all privileges on *.* to 'root'@'%' with grant option;"
# 创建主从账号
mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "create user '${MYSQL_REPLICATION_USER}' identified with mysql_native_password by '${MYSQL_REPLICATION_PASSWORD}';"
mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "grant replication slave on *.* to '${MYSQL_REPLICATION_USER}'@'%';"
mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "flush privileges;"
mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "reset master;"
else
# 当前为从节点
# 设置slave连接master
mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e \
"change master to master_host='svc-mysql-write.ns-mysql', master_port=3306, \
master_user='${MYSQL_REPLICATION_USER}', master_password='${MYSQL_REPLICATION_PASSWORD}', \
master_log_file='master-bin.000001', master_log_pos=156;"
# 重置slave
mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "reset slave;"
# 开始同步
mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "start slave;"
# 改成只读模式
mysql -uroot -p${MYSQL_ROOT_PASSWORD} -e "set global read_only=1;"
fi
touch mysqlInitLock
fi
#livenessProbe:
# exec:
# command: ["mysqladmin", "ping", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"]
# initialDelaySeconds: 30
# periodSeconds: 10
# timeoutSeconds: 5
#readinessProbe:
# exec:
# command: ["mysqladmin", "ping", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"]
# initialDelaySeconds: 5
# periodSeconds: 2
# timeoutSeconds: 1
volumes:
- name: config-map
configMap:
name: cm-mysql-ms
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- "ReadWriteOnce"
storageClassName: nfs-storage-class
resources:
requests:
storage: 1Gi
- metadata:
name: conf
spec:
accessModes:
- "ReadWriteOnce"
storageClassName: nfs-storage-class
resources:
requests:
storage: 50Mi
- metadata:
name: init-sql
spec:
accessModes:
- "ReadWriteOnce"
storageClassName: nfs-storage-class
resources:
requests:
storage: 50Mi
- service.yaml
apiVersion: v1
kind: Service
metadata:
name: svc-mysql-write
namespace: ns-mysql
spec:
type: NodePort
ports:
- name: mysql-write-port
port: 3306 # Service 端口
nodePort: 32306 # 绑定到node的端口(对外暴露的端口)
selector:
app: mysql
statefulset.kubernetes.io/pod-name: sts-mysql-ms-0 # 选择主节点
---
apiVersion: v1
kind: Service
metadata:
name: svc-mysql-read
namespace: ns-mysql
labels:
app: mysql
spec:
type: NodePort
ports:
- name: mysql-read-port
port: 3306
nodePort: 32316
selector:
app: mysql
- 执行helm命令
创建主从集群
helm install mysql-ms ./mysql-ms-8.0.21
查看helm应用
helm list
卸载命令
helm uninstall mysql-ms
总结
以上就是在Kubernetes中搭建MySql集群的所有步骤,请大家安装版本时最好选择的版本与我保持一致,因为不同的版本可能会碰到一些意想不到的问题,避免踩坑。