继上次k8s集群部署完成之后,接下来开始对集群做简单的测试。
首先这里文件存储的方式采用nfs,因此先得部署本地nfs服务器来做后续测试。
环境准备
- nfs服务器centos7.8(阿里云ECS)
机器名: k8s-master
公网ip:47.9x.17x.9x
- nfs客户端centos7.9(腾讯云EVM)
机器名: k8s-node1
公网ip:121.4x.9x.7x
nfs服务器搭建(服务器和客户端都需要安装)
yum -y install rpcbind nfs-utils
# 启动nfs,并开机自启
systemctl start rpcbind
systemctl enable rpcbind
# NFS依赖rpcbind进行通讯,所以要先启动rpcbind
systemctl start nfs-server
systemctl enable nfs-server
# 查看服务是否已启动(服务端和客户端都要测试)
rpcinfo -p localhost
一般showmount -e localhost命令都是好使的,在使用showmount -e 公网ip时会显示如下问题
showmount -e 47.9x.17x.9x
clnt_create: RPC: Port mapper failure - Timed out
出现这问题就说明nfs的端口没有对外开放,服务端需要开放的端口如下:
协议 | 方向 | 端口 | 源地址 | 说明 |
---|---|---|---|---|
UDP | 入站 | 111/111 | 0.0.0.0/0 | nfs portmapper |
TCP | 入站 | 111/111 | 0.0.0.0/0 | nfs portmapper |
UDP | 入站 | 20048/20048 | 0.0.0.0/0 | nfs mountd |
TCP | 入站 | 20048/20048 | 0.0.0.0/0 | nfs mountd |
TCP | 入站 | 2049/2049 | 0.0.0.0/0 | nfs |
UDP | 入站 | 2049/2049 | 0.0.0.0/0 | nfs |
至此,nfs的服务端和客户端就安装成功了,客户端不用开通这些端口。
在nfs服务器创建 挂载目录
mkdir -pv /data/volumes
然后可以再这里目录里创建 nginx default v2 v3 v5 这5个目录供后续测试使用
# 可以共享给指定IP(192.168.1.7),也可以共享给指定网段(192.168.1.0/16),还可以共享给所有IP(*).rw代表读写权限。
vim /etc/exports
/data/volumes/nginx 47.9x.17x.9x(insecure,rw,async,no_root_squash)
/data/volumes/nginx 121.4x.9x.7x(insecure,rw,async,no_root_squash)
此处我将两台服务器都配置了挂载目录的权限
/etc/exports配置文件中权限参数常用的有如下五个:
ro只读权限
rw读写权限
sync同步写入内存与磁盘当中
no_all_squash保留共享文件的UID和GID(默认)
no_root_squash使得root用户具有根目录的完全访问权限
# 重新读取配置文件,而不中断服务
exportfs -rv
# 成功后在两台服务器上都重新执行看目录是否挂载成功
showmount -e 47.9x.17x.9x
可以看到目录共享成功
节点上将挂载点挂载到nfs服务的共享目录(选做,这是测试nfs用,不涉及到k8s后续操作)
mount -t nfs 47.9x.17x.9x:/data/volumes /mnt
可能会报错误: mount: can't find /mnt in /etc/fstab
首先解释下命令含义,mount常用来挂载文件系统,本质nfs就是一个文件系统。上面命令就是将客户端目录/data/volumes做为挂载点,挂载到nfs服务端的共享目录/mnt下,nfs服务端的ip是47.9x.17x.9x。通俗讲就是将客户端目录/data/volumes与服务端的共享目录/mnt实现共享。
执行此命令之前必须保证nfs服务端的export文件内已经配置/mnt为共享目录了。
接着继续看我们的问题,/etc/fstab文件是配置nfs挂载点的文件,问题也就很明显了,我们需要在该文件的末尾新增一行配置一个挂载点,配置如下。
47.9x.17x.9x:/mnt /data/volumes nfs default 0 0
第一列是需要挂载的文件系统或者是存储设备或者是需要挂载的目录。
第二列是挂载点,挂载点就是客户端挂载的目录。
第三列是文件系统或者是分区的类型(其实分区类型就是中文件系统)
第四列是以何种形式挂载,比如rw读写, auto自动挂载,ro只读等等参数。不过最常用的是default。default是rw,suid,dev,exec,auto,nouser,async等的组合。
第五列为dump选项,设置是否让备份程序dump备份文件系统,0为忽略,1为备份。
第六列为fsck选项,告诉fsck程序以什么顺序检查文件系统,0为忽略。
设置完毕后重新执行挂载
mount -t nfs 47.9x.17x.9x:/data/volumes /mnt
成功后分别在nfs服务器和节点服务器做文件测试,会发现是双方同步
卸载挂载目录
umount /mnt
如果提示设备繁忙,那么先退出当前连接,重新连接服务器再执行该命令
创建k8s集群的pv
PV 的全称是:PersistentVolume(持久化卷),是对底层的共享存储的一种抽象,PV 由管理员进行创建和配置,它和具体的底层的共享存储技术的实现方式有关,比如 Ceph、GlusterFS、NFS 等,都是通过插件机制完成与共享存储的对接。
执行以下脚本
vim pv.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nginx
labels:
name: pv-nginx
spec:
nfs:
path: /data/volumes/nginx
server: 47.9x.17x.9x
accessModes: ['ReadWriteMany', 'ReadWriteOnce']
capacity:
storage: 500Mi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv002
labels:
name: pv002
spec:
nfs:
path: /data/volumes/v2
server: 47.9x.17x.9x
accessModes: ['ReadWriteMany', 'ReadWriteOnce']
capacity:
storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv003
labels:
name: pv003
spec:
nfs:
path: /data/volumes/v3
server: 47.9x.17x.9x
accessModes: ['ReadWriteMany', 'ReadWriteOnce']
capacity:
storage: 2Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-default
labels:
name: pv-default
spec:
nfs:
path: /data/volumes/default
server: 47.9x.17x.9x
accessModes: ['ReadWriteMany', 'ReadWriteOnce']
capacity:
storage: 4Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv005
labels:
name: pv005
spec:
nfs:
path: /data/volumes/v5
server: 47.9x.17x.9x
accessModes: ['ReadWriteMany', 'ReadWriteOnce']
capacity:
storage: 7Gi
执行
kubectl apply -f pv.yml
查看创建好的5个pv。可以发现这里pv的存储方式采用的是nfs
kubectl get pv -o wide
可以看到5个新建的pv状态都是未绑定状态,请忽略上述的pv-nginx的状态,这是我后续绑定了pvc造成的,后续会说明。
pv创建好之后,接下来需要使用它。
创建pvc
PVC的全称是: PersistenVolumeClaim (持久化卷声明),PVC是用户存储的一种声明,PVC和Pod比较类型,Pod是消耗节点,PVC消耗的是PV资源,Pod可以请求CPU的内存,而PVC可以请求特定的存储空间和访问模式。对于真正存储的用户不需要关心底层的存储实现细节,只需要直接使用PVC即可
vim pvc-nginx.yml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-nginx
namespace: nginx
spec:
accessModes: ['ReadWriteMany']
resources:
requests:
storage: 500Mi
上述代码可以看到pvc其实并没有指定需要使用哪个pv,只是说明了需要的存储空间是500M(G的写法是Gi),然后访问模式是多次读写(ReadWriteMany)。
首先需要明白一点,存储卷 (PV) 的访问模式 () 决定的是 PV 支持那几种被节点 (nodes) 挂载的方式,。一个存储卷 (PV) 可支持多种模式。几种模式如下:
* (RWO) ReadWriteOnce 可被一个节点读写挂载
* (ROX) ReadOnlyMany 可被多个节点只读挂载
* (RWX) ReadWriteMany 可被多个节点读写挂载
执行
kubectl apply -f pvc-nginx.yml
然后在查看pv使用情况,就会发现是我上面截图的那种情况,pv会根据pvc申请的空间大小自动去匹配合适的pv卷,然后进行绑定,刚好pv-nginx满足他的需要,因此nginx和pvc绑定成功。
pvc的查看命令是:
创建nginx deployment
先单独创建nginx 的namespace
kubectl create namespace nginx
接下来使用nginx的测试都在nginx namespace中进行。
创建nginx configmap文件
configmap文件用来存储nginx.conf配置文件。之所以将nginx的配置文件和nginx的pod分开部署,是由于在大部分情况下nginx服务本身其实并不会改动,改动的也只是nginx配置文件,所以单独拿出来部署。
而部署nginx配置文件其实有很多种方式,可以使用configmap,也可以使用pvc来将配置文件挂载到本地或者其他的储存文件系统中去。
另外要注意的一点是,configmap文件可以随时更改。但是nginx配置文件更改之后,通常情况下需要nginx reload。而且nginx采用deployment部署的话,你即使重新apply -f deployment文件的话,它也不会起作用。因为此时的deployment文件并没有任何改动,k8s会认为该pod没有做变动,不会重新启动pod。这一点在后续会说明,可以采用别的方式来强制apply -f deplyment文件。
vim nginx-configmap.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-configmap
namespace: nginx
data:
nginx_conf: |-
#user nobody;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location /data {
root /usr/share/nginx;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}
此处的nginx 添加了/data 映射是为了后续访问index.html首页时能实时打印出当前节点的hostname,以便能明显区分出k8s对pod的负载均衡功能。
执行configmap文件
kubectl apply -f nginx-configmap.yml
查看cm
kubectl -n nginx get cm -o wide
创建nginx deployment文件
vim nginx-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-cluster
name: nginx-cluster
namespace: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx-cluster
template:
metadata:
labels:
app: nginx-cluster
spec:
containers:
- name: nginx-cluster
image: nginx
command:
- /bin/sh
args:
- '-c'
- |
set -ex
mkdir -pv /usr/share/nginx/data
echo $HOSTNAME>/usr/share/nginx/data/hostname.data
exec nginx -g 'daemon off;'
env:
- name: RESTART_
value: v202012101554
ports:
- containerPort: 80
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
- name: nginx
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: html
persistentVolumeClaim:
claimName: pvc-nginx
- name: nginx
configMap:
name: nginx-configmap
items:
- key: nginx_conf
path: nginx.conf
这里着重说下command、args和env三个属性,command属性用来输入命令,一般建议就输入/bin/sh即可,想执行多条shell命令的话,在args中输入,-c用来解析后面的字符串执行其中的指令,文件中的命令很简单,先创建目录,再将主机名输入该目录下的文件中存储。唯一注意的是最后的这条命令 exec nginx -g 'daemon off;' 。
Docker 容器启动时,默认会把容器内部第一个进程,也就是pid=1的程序,作为docker容器是否正在运行的依据,如果 docker 容器pid=1的进程挂了,那么docker容器便会直接退出。
Docker未执行自定义的CMD之前,nginx的pid是1,执行到CMD之后,nginx就在后台运行,bash或sh脚本的pid变成了1。
所以一旦执行完自定义CMD,nginx容器也就退出了。
上述这一点在今后部署服务时一定要注意。
而env中的环境参数就是用来控制deployment文件强制重启的,每次想重新启动deployment的话,直接修改RESATRT_的值,然后再执行 kubectl apply -f deployment.yml 即可。
创建nginx deployment
kubectl apply -f nginx-deployment.yml
查看运行情况
kubectl -n nginx get pod -o wide
会发现nginx的两个pod已经运行起来了,它运行的机器是由k8s自行调度的,本文这里是刚好俩pod都调度到了k8s-node1节点上。
现在在k8s-mater节点和k8s-node1节点分别ping这俩ip地址。如果都能ping通的话说明集群间的地址通讯没有问题。
将index.html文件放入nfs服务器中的/data/volumes/nginx目录下面
Document
hello。
再检查 curl 10.244.1.3:80 或者curl 10.244.1.2:80 看能不能请求成功。
都成功的话现在部署svc,通过svc来对外暴露pod
创建nginx service
vim nginx-service.yml
apiVersion: v1
kind: Service
metadata:
name: nginx-service #定义service名称为nginx-service
namespace: nginx
labels:
app: nginx-service #为service打上app标签
spec:
type: NodePort #使用NodePort方式开通,在每个Node上分配一个端口作为外部访问入口
selector:
app: nginx-cluster
ports:
- port: 8000 #port是k8s集群内部访问service的端口,即通过clusterIP: port可以访问到某个service
targetPort: 80 #targetPort是pod的端口,从port和nodePort来的流量经过kube-proxy流入到后端pod的targetPort上,最后进入容器
nodePort: 32500 #nodePort是外部访问k8s集群中service的端口,通过nodeIP: nodePort可以从外部访问到某个service
执行
kubectl apply -f nginx-serivce.yml
查看
kubectl get svc -n nginx -o wide
可以看到svc也部署成功
先测试看该ip地址能否在master和node1节点上都能ping通,
检查 curl 10.1.220.172:8000 能否请求成功
都没问题的话即可以使用外用ip访问32500端口了。
47.9x.17x.9x和121.4x.9x.7x这两个外网地址访问32500都可以
多开几个客户端请求地址查看。可以发现每次返回的主机名都不一样。
至此,验证工作完成。接下来是完善k8s生态,待后续。