🎈「k8s 探索」系列:
前面我们已经搭建好了一个基础的 k8s 集群,也运行一个「无状态」的应用,但很多服务是有状态的,比如常见的关系型数据库 MySQL
,下面我们就一起尝试安装一个简单的 MySQL 单实例应用。
1 部署 NFS 存储
在部署之前,先来想想数据库中的数据存在哪里。你可能说这还不简单,直接存在本机的硬盘里就可以了,这样做确实可以!但这样是不是就没法让 k8s 根据随意调度 pod 到不同的节点上去了。
如果一开始 pod 和 data 都在 server1,突然 server1 断了, pod 就会转移到 server2, 但是 server2 无法访问 server1 的数据。因此一个「网络存储」是比较通用的做法,但这也不一定是最优的,只能说是一个简单通用的方法。
网络文件系统(NFS
Network File System)是一种分布式文件系统,力求客户端主机可以访问服务器端文件,并且其过程与访问本地存储时一样,它由Sun微系统开发,于1984年发布。
下面我们来配置 NFS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| # 为所有节点安装 nfs-common sudo apt install nfs-common
# 在存储节点上安装 nfs-common sudo apt install nfs-kernel-server
# 创建共享目录 mkdir /mnt/nfs_share chmod -R 777 /mnt/nfs_share
# 添加访问权限 sudo vim /etc/exports # 在最后一行写入 /mnt/nfs_share 192.168.2.0/24(rw,sync,no_subtree_check,no_root_squash)
# 启动 nfs 服务 sudo service nfs-kernel-server start
# 检验是否成功开启 sudo showmount -e 192.168.2.102 # Export list for 192.168.2.102: # /mnt/nfs_share 192.168.2.0/24
git clone https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner
cd nfs-subdir-external-provisioner/deploy # 手动下载镜像 docker pull lank8s.cn/sig-storage/nfs-subdir-external-provisioner:v4.0.2 docker tag lank8s.cn/sig-storage/nfs-subdir-external-provisioner:v4.0.2 192.168.2.101:5000/sig-storage/nfs-subdir-external-provisioner:v4.0.2 docker push 192.168.2.101:5000/sig-storage/nfs-subdir-external-provisioner:v4.0.2
vim deployment.yaml
# 修改镜像地址,把 k8s.gcr.io 修改为 192.168.2.101:5000
# 把 10.3.243.101 和 /ifs/kubernetes 修改为 192.168.2.102 和 /mnt/nfs_share - name: NFS_SERVER value: 192.168.2.102 - name: NFS_PATH value: /mnt/nfs_share volumes: - name: nfs-client-root nfs: server: 192.168.2.102 path: /mnt/nfs_share
vim class.yaml # 删除掉以下参数,这样做可以在删除 PV 时,会自动归档 parameters: archiveOnDelete: "false"
# 运行 kubectl apply -k .
|
可以通过查看 pvc、pod 中的 test-claim、test-pod,检查功能是否正常。
2 部署 MySQL
现在正式来部署一个单实例的 MySQL 应用。
1 2 3
| # 创建应用目录 mkdir mysql cd mysql
|
第一步,将密码保存入 secret 中,用于保证数据的安全性。
1 2 3
| echo -n "Qwer1234" | base64 UXdlcjEyMzQ=
|
1 2 3 4 5 6 7 8
| apiVersion: v1 kind: Secret metadata: name: mysql type: Opaque data: password: UXdlcjEyMzQ=
|
第二步,使用 nfc-client 声明 pvc,并可以自动申请存储。
1 2 3 4 5 6 7 8 9 10 11 12
| apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql spec: storageClassName: nfs-client accessModes: - ReadWriteMany resources: requests: storage: 10Gi
|
第三步,创建服务,并暴露 30060 端口。(端口为了测试使用,原则上不暴露到外网最为安全)
1 2 3 4 5 6 7 8 9 10 11 12
| apiVersion: v1 kind: Service metadata: name: mysql spec: type: NodePort ports: - port: 3306 nodePort: 30060 selector: app: mysql
|
第四步,创建一个 Deployment,用于控制 pod。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| apiVersion: apps/v1 kind: Deployment metadata: name: mysql spec: selector: matchLabels: app: mysql strategy: type: Recreate template: metadata: name: mysql labels: app: mysql spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: type operator: In values: - storage containers: - image: mysql/mysql-server:8.0.27-aarch64 name: mysql env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql key: password ports: - containerPort: 3306 name: mysql volumeMounts: - name: mysql-persistent-storage mountPath: /var/lib/mysql volumes: - name: mysql-persistent-storage persistentVolumeClaim: claimName: mysql
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| # 在 mysql 文件夹下 kubectl apply -f ./
# 等20秒后,查看 pod 是否正常启动 kubectl get pod | grep mysql # mysql-xxxxxxxxxx-xxxxx 1/1 Running 0 20s
# 创建远程只读账户 kubectl exec -it mysql-xxxxxxxxxx-xxxxx -- mysql -u root -p # 输入密码 Qwer1234 进入 # 创建一个原创只读账户 readonly 123456 mysql> CREATE USER 'readonly'@'%' IDENTIFIED BY '123456'; mysql> GRANT SElECT ON *.* TO 'readonly'@'%' WITH GRANT OPTION; mysql> FLUSH PRIVILEGES;
# 在远程继续连接测试 # 替换掉 $remote_host 和 $remote_port mysql -h $remote_host -P $remote_port -u readonly -p # 输入密码 123456 进入 mysql>
# 重新使用 root 用户进入 # 删除只读账户 readonly mysql> DROP USER 'readonly'@'%';
|
恭喜你🎉,这样一个简单的有状态单实例应用就部署完成了!
目前 ARM 生态的东西还不完善,因此我无法完成 MySQL 集群的部署。在生产环境中,推荐使用 StatefulSet
部署的 MySQL 集群。
参考
🎈「k8s 探索」系列: