k8s 探索8:运行一个简单的「有状态」的应用

k8s 探索8:运行一个简单的「有状态」的应用

🎈「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
# 使用 base64 对密码文本进行编码
echo -n "Qwer1234" | base64
UXdlcjEyMzQ=
1
2
3
4
5
6
7
8
# mysql/secret.yaml
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
# mysql/pvc.yaml
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
# mysql/svc.yaml
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
# mysql/deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mysql
spec:
selector:
matchLabels:
app: mysql
strategy:
type: Recreate
template:
metadata:
name: mysql
labels:
app: mysql
spec:
# 节点亲和性,选取 type: storage 的节点
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 探索」系列:

评论