# Headless Service。类似绑定了mysql-0的IP地址# 通过为 Pod 分配 DNS 记录来固定它的拓扑状态,比如“mysql-0.mysql”和“mysql-1.mysql”这样的 DNS 名字# 其中,编号为 0 的节点就是我们的主节点# 写请求,则必须直接以 DNS 记录的方式访问到 MySQL 的主节点apiVersion: v1
kind: Service
metadata:name: mysql
labels:app: mysql
spec:ports:-name: mysql
port:3306clusterIP: None
selector:app: mysql
---# 常规的 Service。用于负载均衡# 所有用户的读请求,都必须访问第二个 Service 被自动分配的 DNS 记录# 即:“mysql-read”(当然,也可以访问这个 Service 的 VIP)# 读请求就可以被转发到任意一个 MySQL 的主节点或者从节点上apiVersion: v1
kind: Service
metadata:name: mysql-read
labels:app: mysql
spec:ports:-name: mysql
port:3306selector:app: mysql
创建service资源
kubectl apply -f mysql-services.yaml
StatefulSet
mysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:name: mysql
spec:selector:# 这个 StatefulSet 要管理的 Pod 必须携带 app=mysql 标签# 它声明要使用的 Headless Service 的名字是:mysqlmatchLabels:app: mysql
app.kubernetes.io/name: mysql
serviceName: mysql
# 这个 StatefulSet 的 replicas 值是 3,表示它定义的 MySQL 集群有三个节点# 一个 Master 节点,两个 Slave 节点replicas:3template:metadata:labels:app: mysql
app.kubernetes.io/name: mysql
spec:# InitContainer 应该是排头兵,做了一系列的准备工作:确定M/S角色、拷贝配置文件、挂载存储卷# 当 InitContainer 复制完配置文件退出后,后面启动的 MySQL 容器只需要直接声明挂载这个名叫 conf 的 Volume# 它所需要的.cnf 配置文件已经出现在里面了initContainers:-name: init-mysql
image: mysql:5.7command:- bash
-"-c"-|
set -ex
# 从Pod的序号, 生成server-id
# 通过这个序号,判断当前 Pod 到底是 Master 节点(即:序号为 0)还是 Slave 节点(即:序号不为 0)
[[ $HOSTNAME =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
echo [mysqld] > /mnt/conf.d/server-id.cnf
# 由于server-id=0有特殊含义, 我们给ID加一个100来避开它
echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
# 如果Pod序号是0, 说明它是Master节点, 从ConfigMap里把Master的配置文件拷贝到/mnt/conf.d/目录. 否则,拷贝Slave的配置文件
if [[ $ordinal -eq 0 ]]; then
cp /mnt/config-map/primary.cnf /mnt/conf.d/
else
cp /mnt/config-map/replica.cnf /mnt/conf.d/
fi volumeMounts:# 而文件拷贝的目标目录,即容器里的 /mnt/conf.d/ 目录# 对应的则是一个名叫 conf 的、emptyDir 类型的 Volume-name: conf
mountPath: /mnt/conf.d
# ConfigMap 里保存的内容,就会以文件的方式出现在它的 /mnt/config-map 目录-name: config-map
mountPath: /mnt/config-map
-name: clone-mysql
# 在 Slave Pod 启动前,从 Master 或者其他 Slave Pod 里拷贝数据库数据到自己的目录下# image: yizhiyong/xtrabackup
command:- bash
-"-c"-|
set -ex
# 拷贝操作只需要在第一次启动时进行,所以如果数据已经存在,跳过
[[ -d /var/lib/mysql/mysql ]] && exit 0
# Master节点(序号为0)不需要做这个操作
[[ `hostname` =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
[[ $ordinal -eq 0 ]] && exit 0
# 使用ncat指令,远程地从前一个节点拷贝数据到本地.保证上一个pod是启动运行状态的
# 3307 是一个特殊端口,运行着一个专门负责备份 MySQL 数据的辅助进程
ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql
# 执行--prepare,这样拷贝来的数据就可以用作恢复了
xtrabackup --prepare --target-dir=/var/lib/mysql volumeMounts:-name: data
mountPath: /var/lib/mysql
subPath: mysql
-name: conf
mountPath: /etc/mysql/conf.d
containers:-name: mysql
image: mysql:5.7env:-name: MYSQL_ALLOW_EMPTY_PASSWORD
value:"1"ports:-name: mysql
containerPort:3306volumeMounts:-name: data
mountPath: /var/lib/mysql
subPath: mysql
-name: conf
mountPath: /etc/mysql/conf.d
resources:requests:cpu: 500m
memory: 1Gi
livenessProbe:exec:command:["mysqladmin","ping"]initialDelaySeconds:30periodSeconds:10timeoutSeconds:5readinessProbe:exec:# Check we can execute queries over TCP (skip-networking is off).command:["mysql","-h","127.0.0.1","-uroot","-e","SELECT 1"]initialDelaySeconds:5periodSeconds:2timeoutSeconds:1-name: xtrabackup
# 如何在 Slave 节点的 MySQL 容器第一次启动之前,执行初始化 SQLimage: yizhiyong/xtrabackup
ports:-name: xtrabackup
containerPort:3307command:- bash
-"-c"-|
set -ex
cd /var/lib/mysql# 从备份信息文件里读取MASTER_LOG_FILEM和MASTER_LOG_POS这两个字段的值,用来拼装集群初始化SQL
if [[-f xtrabackup_slave_info && "x$(<xtrabackup_slave_info)" != "x" ]]; then
# 如果xtrabackup_slave_info文件存在,说明这个备份数据来自于另一个Slave节点# 这种情况下,XtraBackup工具在备份的时候,就已经在这个文件里自动生成了"CHANGE MASTER TO" SQL语句# 所以,我们只需要把这个文件重命名为change_master_to.sql.in,后面直接使用即可
cat xtrabackup_slave_info | sed -E 's/;$//g' > change_master_to.sql.in
# 所以,也就用不着xtrabackup_binlog_info了
rm -f xtrabackup_slave_info xtrabackup_binlog_info
elif [[-f xtrabackup_binlog_info ]]; then
# 如果只存在xtrabackup_binlog_inf文件,那说明备份来自于Master节点# 我们就需要解析这个备份信息文件,读取所需的两个字段的值[[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$]]|| exit 1
rm -f xtrabackup_binlog_info xtrabackup_slave_info
echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}',\
MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in
fi
# 如果change_master_to.sql.in存在,就意味着需要做集群初始化工作
if [[-f change_master_to.sql.in ]]; then
# 但一定要先等MySQL容器启动之后才能进行下一步连接MySQL的操作
echo "Waiting for mysqld to be ready (accepting connections)"
until mysql -h 127.0.0.1 -e "SELECT 1"; do sleep 1; done
echo "Initializing replication from clone position"
# 将文件change_master_to.sql.in改个名字,防止这个Container重启的时候# 因为又找到了change_master_to.sql.in,从而重复执行一遍这个初始化流程
mysql -h 127.0.0.1 \
-e "$(<change_master_to.sql.in), \
MASTER_HOST='mysql-0.mysql', \
MASTER_USER='root', \
MASTER_PASSWORD='', \
MASTER_CONNECT_RETRY=10; \
START SLAVE;" || exit 1
# 使用change_master_to.sql.orig的内容,也是就是前面拼装的SQL,组成一个完整的初始化和启动Slave的SQL语句
mv change_master_to.sql.in change_master_to.sql.orig
fi
# 使用ncat监听3307端口。它的作用是,在收到传输请求的时候# 直接执行"xtrabackup --backup"命令,备份MySQL的数据并发送给请求者
exec ncat --listen --keep-open --send-only --max-conns=1 3307 -c \
"xtrabackup --backup --slave-info --stream=xbstream --host=127.0.0.1 --user=root"
volumeMounts:-name: data
mountPath: /var/lib/mysql
subPath: mysql
-name: conf
mountPath: /etc/mysql/conf.d
resources:requests:cpu: 100m
memory: 100Mi
volumes:-name: conf
emptyDir:{}# 一个名叫 conf 的、emptyDir 类型的 Volume-name: config-map
configMap:name: mysql
# PVC 模板。来为每个 Pod 定义 PVC# 这个 PVC 模板的 resources.requests.strorage 指定了存储的大小为 10 GiBvolumeClaimTemplates:-metadata:name: data
spec:storageClassName: rook-ceph-block
# ReadWriteOnce 指定了该存储的属性为可读写,并且一个 PV 只允许挂载在一个宿主机上accessModes:["ReadWriteOnce"]resources:requests:storage: 10Gi
[root@master ~]# kubectl logs mysql-0 init-mysql
+ [[ mysql-0 =~ -([0-9]+)$ ]]
+ ordinal=0
+ echo'[mysqld]'
+ echo server-id=100
+ [[0-eq0]]
+ cp /mnt/config-map/primary.cnf /mnt/conf.d/
[root@master ~]# kubectl logs mysql-0 mysql2023-03-24 07:09:15+00:00 [Note][Entrypoint]: Entrypoint script for MySQL Server 5.7.36-1debian10 started.
2023-03-24 07:09:15+00:00 [Note][Entrypoint]: Switching to dedicated user 'mysql'2023-03-24 07:09:15+00:00 [Note][Entrypoint]: Entrypoint script for MySQL Server 5.7.36-1debian10 started.
2023-03-24T07:09:15.578039Z 0[Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation formore details).
2023-03-24T07:09:15.579656Z 0[Note] mysqld (mysqld 5.7.36-log) starting as process 1...
2023-03-24T07:09:15.580982Z 0[Warning] No argument was provided to --log-bin, and --log-bin-index was not used; so replication may break when this MySQL server acts as a master and has his hostname changed!! Please use '--log-bin=mysql-0-bin' to avoid this problem.
2023-03-24T07:09:15.607203Z 0[Note] InnoDB: PUNCH HOLE support available
2023-03-24T07:09:15.607219Z 0[Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
2023-03-24T07:09:15.607222Z 0[Note] InnoDB: Uses event mutexes
2023-03-24T07:09:15.607224Z 0[Note] InnoDB: GCC builtin __atomic_thread_fence() is used for memory barrier
2023-03-24T07:09:15.607226Z 0[Note] InnoDB: Compressed tables use zlib 1.2.11
2023-03-24T07:09:15.607229Z 0[Note] InnoDB: Using Linux native AIO
2023-03-24T07:09:15.607506Z 0[Note] InnoDB: Number of pools: 12023-03-24T07:09:15.607671Z 0[Note] InnoDB: Using CPU crc32 instructions
2023-03-24T07:09:15.609449Z 0[Note] InnoDB: Initializing buffer pool, total size = 128M, instances =1, chunk size = 128M
2023-03-24T07:09:15.617162Z 0[Note] InnoDB: Completed initialization of buffer pool
2023-03-24T07:09:15.620370Z 0[Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority().
2023-03-24T07:09:15.644357Z 0[Note] InnoDB: Highest supported fileformat is Barracuda.
2023-03-24T07:09:16.057153Z 0[Note] InnoDB: Creating shared tablespace for temporary tables
2023-03-24T07:09:16.057222Z 0[Note] InnoDB: Setting file'./ibtmp1' size to 12 MB. Physically writing the file full; Please wait...
2023-03-24T07:09:19.387580Z 0[Note] InnoDB: File './ibtmp1' size is now 12 MB.
2023-03-24T07:09:19.388076Z 0[Note] InnoDB: 96 redo rollback segment(s) found. 96 redo rollback segment(s) are active.
2023-03-24T07:09:19.388095Z 0[Note] InnoDB: 32 non-redo rollback segment(s) are active.
2023-03-24T07:09:19.388889Z 0[Note] InnoDB: Waiting for purge to start
2023-03-24T07:09:19.446231Z 0[Note] InnoDB: 5.7.36 started; log sequence number 126661492023-03-24T07:09:19.447072Z 0[Note] InnoDB: Loading buffer pool(s) from /var/lib/mysql/ib_buffer_pool
2023-03-24T07:09:19.447166Z 0[Note] Plugin 'FEDERATED' is disabled.
2023-03-24T07:09:19.694456Z 0[Note] InnoDB: Buffer pool(s) load completed at 2303247:09:19
2023-03-24T07:09:19.787835Z 0[Note] Found ca.pem, server-cert.pem and server-key.pem in data directory. Trying to enable SSL support using them.
2023-03-24T07:09:19.787892Z 0[Note] Skipping generation of SSL certificates as certificate files are present in data directory.
2023-03-24T07:09:19.787897Z 0[Warning] A deprecated TLS version TLSv1 is enabled. Please use TLSv1.2 or higher.
2023-03-24T07:09:19.787898Z 0[Warning] A deprecated TLS version TLSv1.1 is enabled. Please use TLSv1.2 or higher.
2023-03-24T07:09:19.790876Z 0[Warning] CA certificate ca.pem is self signed.
2023-03-24T07:09:19.790926Z 0[Note] Skipping generation of RSA key pair as key files are present in data directory.
2023-03-24T07:09:19.794145Z 0[Note] Server hostname(bind-address): '*'; port: 33062023-03-24T07:09:19.794362Z 0[Note] IPv6 is available.
2023-03-24T07:09:19.794440Z 0[Note] - '::' resolves to '::';2023-03-24T07:09:19.794469Z 0[Note] Server socket created on IP: '::'.2023-03-24T07:09:19.795754Z 0[Warning] Insecure configuration for --pid-file: Location '/var/run/mysqld'in the path is accessible to all OS users. Consider choosing a different directory.
2023-03-24T07:09:20.029315Z 0[Note] Failed to start slave threads for channel ''2023-03-24T07:09:20.567496Z 0[Note] Event Scheduler: Loaded 0 events
2023-03-24T07:09:20.568119Z 0[Note] mysqld: ready for connections.
Version: '5.7.36-log' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)2023-03-24T07:09:46.837520Z 9[Warning] IP address '10.244.4.62' could not be resolved: Name or service not known
2023-03-24T07:09:46.844496Z 9[Note] Start binlog_dump to master_thread_id(9) slave_server(101), pos(mysql-0-bin.000006, 756)2023-03-24T07:10:40.115743Z 43[Warning] IP address '10.244.3.116' could not be resolved: Name or service not known
2023-03-24T07:10:40.173087Z 43[Note] Start binlog_dump to master_thread_id(43) slave_server(102), pos(mysql-0-bin.000006, 756)
[root@master ~]# kubectl get pod -l app=mysql
NAME READY STATUS RESTARTS AGE
mysql-0 2/2 Running 0 4m5s
mysql-1 2/2 Running 0 3m10s
mysql-2 2/2 Running 0 2m45s
表创建
kubectl run mysql-client --image=mysql:5.7 -i --rm --restart=Never --\
mysql -h mysql-0.mysql -uroot -e'
CREATE DATABASE test;
CREATE TABLE test.messages (message VARCHAR(250));
INSERT INTO test.messages VALUES ('hello');
'
表查询
kubectl run mysql-client --image=mysql:5.7 -i --rm --restart=Never -- mysql -h mysql-read -uroot -e'SELECT * FROM test.messages'
If you don't see a command prompt, try pressing enter.
message
hello
pod "mysql-client" deleted