pv和pvc存储 - nfs
RC、RS、Deployment 可以控制副本数量,但需要所有 Pod 副本使用的数据与 Pod 自身的生命周期分离,这就需要用额外的空间存储这些数据。
PV(Persistent Volume),是一个全局资源,在创建之初定义了有多大的存储能力。
PVC(Persistent Volume Claim),是 Namespace 中的资源,描述的是对 PV 的一个使用请求。
每个需要使用的 Pod 需要有一个 PVC 与全局的 PV 相绑定,并且声明自己使用 PV 的多大空间。
安装 nfs
每个节点需要有 nfs 的客户端,nfs 的服务端可以只有一个。(C/S模式)
yum install nfs-utils -y # 所有节点安装客户端
配置 nfs 访问
以下配置,共享 /data 目录,使用 192.168.208.0/24 段访问,读写,同步、指定不做 root 用户的 uid 映射,不做其他用户的 uid 映射。
# vim /etc/exports
/data 192.168.208.0/24(rw,async,no_root_squash,no_all_squash) #
重启 rpcbind 和 nfs
systemctl restart rpcbind
systemctl restart nfs #
systemctl enable nfs # 记得设置为开机自启动
nfs 启动状态错误
image.png
原来是因为括号中是逗号而不是空格,教程上没体现到变动。以上代码已经是修正版的了
验证安装成功
在任何一台机器上通过 showmount -e 192.168.208.130
查看是否能查到 nfs。
创建 pv
# pv/test-pv.yml
apiVersion: v1
kind: PersistentVolume
metadata:
name: test
labels:
type: test
spec:
capacity:
storage: 10Gi # 提供 10G 的存储
accessModes:
- ReadWriteMany # 允许多个 Pod 同时读写
persistentVolumeReclaimPolicy: Recycle # pvc 的策略,允许回收
nfs:
path: "/data/k8s"
server: 192.168.208.130 #
readOnly: false # 取消只读,就是可写
kubectl create -f pv/test-pv.yml # persistentvolume "test" created
以下通过更改名字和空间大小,创建了三个 pv,查看 pv:
image.png创建 pvc
# test-pvc.yml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nfs # pvc 的名字
spec:
accessModes:
- ReadWriteMany # 模式允许多人读写访问
resources:
requests:
storage: 1Gi # 需求资源 1G
image.png
更新 pvc 请求资源量,pvc 会对应使用容量最小能用的 pv 进行绑定。
image.png实践 Pod 使用 nfs pv/pvc
- 写了一个向服务器文件目录中上传文件以及获取文件列表的程序
- 创建 k8s 资源配置文件,使用 pv、pvc、svc、deployment 资源
- 通过 postman 上传文件,通过浏览器查看列表
制作程序:显示文件列表及上传文件
用 go 写一个提供上传/访问文件系统的程序,代码如下:
package main
import (
// ...
"github.com/gin-gonic/gin"
)
var (
filedir = flag.String("d", "./data", "the file dir for server")
port = flag.String("p", "8080", "the port which server is running on")
)
func main() {
flag.Parse()
abs, err := filepath.Abs(*filedir)
if err != nil {
abs = *filedir
}
fmt.Println("the file dir:", abs)
fmt.Println("runing on port:", *port)
fmt.Println()
app := gin.New()
app.GET("/", func(c *gin.Context) {
c.Redirect(301, "/fs")
})
app.StaticFS("/fs", gin.Dir(*filedir, true)) // API:列表指定目录的内容
app.POST("/upload", func(c *gin.Context) { // API 上传文件
datafile, header, err := c.Request.FormFile("datafile")
if err != nil {
c.AbortWithError(400, err)
return
}
defer datafile.Close()
fd, err := os.Create(filepath.Join(*filedir, header.Filename))
if err != nil {
c.AbortWithError(500, err)
return
}
defer fd.Close()
io.Copy(fd, datafile)
})
if err := app.Run(":" + *port); err != nil {
fmt.Println("service run failed:", err.Error())
}
}
使用 CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build .
交叉编译出 linux 上二进制文件。(输出 fs-svr)
构建 Docker
创建 Dockerfile:
FROM 192.168.208.130:5000/alpine:latest
COPY fs-svr /service/
WORKDIR /service
RUN mkdir /data /service/data # RUN 在 build 阶段执行
EXPOSE 9000
ENTRYPOINT ["./fs-svr"] # ENTRYPOINT 的命令在 run 阶段执行,可以和 CMD 拼接到一块
CMD ["-p", "9000", "-d", "/data"] # CMD 在 run 阶段执行,可以认为是默认的启动命令/参数,可以被传入的命令/参数覆盖
注意:
这里使用 alpine 作为基础镜像,注意先从网上下载这个基础镜像,然后改 tag 推到私有镜像库中。
这里用服务名为 fs-svr,并且在服务本地目录位置有个 data 目录是服务内部默认用的目录
通过一系列操作将镜像构建出来并 push 到私有库中:
docker build . # 构建
docker tag 676d70bef0a7 192.168.208.130:5000/fs-svr:0.0.1 # 打私有仓库的标签
docker push 192.168.208.130:5000/fs-svr:0.0.1 # 提交到私有仓库
创建 k8s 资源
编辑 k8s.yml 文件。创建 deployment 和 service 资源
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: fs-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: fs-svr
spec:
containers:
- name: fs-svr
image: 192.168.208.130:5000/fs-svr:0.0.1
ports:
- containerPort: 9000
volumeMounts:
- name: fsdata # 绑定 template 定义的 volumes
mountPath: /data/
volumes: # 与 containers 并级
- name: fsdata # 自定义一个名称,必须小写,用于 containers[].volumeMounts[].name
persistentVolumeClaim: #
claimName: nfs2 # 使用的 pvc 的名字
---
apiVersion: v1
kind: Service # 创建 service,允许通过宿主机访问
metadata:
name: fs-service
spec:
type: NodePort # 端口映射的方式,还有其他支持
ports:
- port: 80 # cluster IP 的端口
nodePort: 30000 # 宿主机的端口(宿主机的端口在配置文件中指定)
targetPort: 9000 # pod 地址的端口
selector: # 为哪些 Pod 做负载均衡是通过标签选择器选择的
app: fs-svr # 选择 app: fs-svr 的 Label
通过 kubectl create -f k8s.yaml
创建资源。创建的资源列表:
测试上传和显示
- 通过浏览器地址
http://k8s-master:30000/fs/
查看文件列表 - 通过 postman 上传文件
curl --location --request POST 'k8s-master:30000/upload' \
--form 'datafile=@"/I:/workspace/k8s/kube-dns-svc.yml"'
- 再次查看浏览器地址文件列表,查看 container 资源内文件列表及 pv 对应目录的文件列表(创建 pv 时有指定
/data/k8s
) -
kubectl delete deployment fs-deployment
删除服务资源或进行更新等操作,查看 pv 对应资源是否持久化(是,成功)
其他技巧
限制重启后 deployment 资源的数量
如上文中下图是因为重复了多次 kubectl apply
资源操作,导致遗留了很多无用的资源信息。
可以通过 deployment.spec.revisionHistoryLimit
来进行限制:
➜ ~ kubectl explain deployment.spec.revisionHistoryLimit
FIELD: revisionHistoryLimit <integer>
DESCRIPTION:
The number of old ReplicaSets to retain to allow rollback. This is a
pointer to distinguish between explicit zero and not specified.
shell 操作没有提示
参考 k8s命令自动补全(只是 bash 使用的,在 zsh 或者说 Oh-my-zsh 上不好用)
kubectl api-resources
kubectl api-resources
可以显示所有 k8s 资源,但目前由于集群版本问题不显示。后面再了解。