目录
转载请注明出处
相关链接
- K8S单机部署-00.旧版本卸载
- K8S单机部署-01.单机部署K8S
- K8S单机部署-02.Kuboard面板部署
- K8S单机部署-03.验证K8S的第一个Deployment
- K8S单机部署-04.NFS服务器搭建
- K8S单机部署-05.静态持久化之PV、PVC(基于NFS)
- K8S单机部署-06.动态持久化StorageClass(基于NFS)
- K8S单机部署-07.调整nodePort端口范围
- K8S单机部署-08.安装ingress-nginx-controller
- K8S单机部署-10.增加自定义域名解析
- K8S单机部署-11.安装Kubernetes Metrics Server监控
一、StorageClass是什么
Kubernetes提供了一套可以自动创建PV的机制,即:Dynamic Provisioning.而这个机制的核心在于:StorageClass这个API对象.
StorageClass对象会定义下面两部分内容:
- PV的属性.比如,存储类型,Volume的大小等.
- 创建这种PV需要用到的存储插件
有了这两个信息之后,Kubernetes就能够根据用户提交的PVC,找到一个对应的StorageClass,之后Kubernetes就会调用该StorageClass声明的存储插件,进而创建出需要的PV.
但是其实使用起来是一件很简单的事情,你只需要根据自己的需求,编写YAML文件即可,然后使用kubectl create命令执行即可
二、StorageClass出现的原因
在一个大规模的Kubernetes集群里,可能有成千上万个PVC,这就意味着运维人员必须实现创建出这个多个PV,此外,随着项目的需要,会有新的PVC不断被提交,那么运维人员就需要不断的添加新的,满足要求的PV,否则新的Pod就会因为PVC绑定不到PV而导致创建失败.而且通过 PVC 请求到一定的存储空间也很有可能不足以满足应用对于存储设备的各种需求
而且不同的应用程序对于存储性能的要求可能也不尽相同,比如读写速度、并发性能等,为了解决这一问题,Kubernetes 又为我们引入了一个新的资源对象:StorageClass,通过 StorageClass 的定义,管理员可以将存储资源定义为某种类型的资源,比如快速存储、慢速存储等,用户根据 StorageClass 的描述就可以非常直观的知道各种存储资源的具体特性了,这样就可以根据应用的特性去申请合适的存储资源了
三、StorageClass运行原理
在动态资源供应模式下,通过StorageClass和PVC完成资源动态绑定(系统自动生成PV),并供Pod使用的存储管理机制。
volumeClaimTemplates实现了pvc的自动化,StorageClass实现了pv的自动化
每个 StorageClass 都包含
provisioner
、parameters
和reclaimPolicy
字段, 这些字段会在 StorageClass 需要动态分配 PersistentVolume 时会使用到。
StorageClass 对象的命名很重要,用户使用这个命名来请求生成一个特定的类。 当创建 StorageClass 对象时,管理员设置 StorageClass 对象的命名和其他参数,一旦创建了对象就不能再对其更新。
管理员可以为没有申请绑定到特定 StorageClass 的 PVC 指定一个默认的存储类
要使用 StorageClass,我们就得安装对应的自动配置程序,比如我们这里存储后端使用的是 nfs,那么我们就需要使用到一个 nfs-client 的自动配置程序,我们也叫它 Provisioner(制备器),这个程序使用我们已经配置好的 nfs 服务器,来自动创建持久卷,也就是自动帮我们创建 PV。
-
- 自动创建的 PV 以
${namespace}-${pvcName}-${pvName}
这样的命名格式创建在 NFS 服务器上的共享数据目录中
- 自动创建的 PV 以
-
- 而当这个 PV 被回收后会以
archieved-${namespace}-${pvcName}-${pvName}
这样的命名格式存在 NFS 服务器上。
- 而当这个 PV 被回收后会以
搭建StorageClass+NFS,大致有以下几个步骤:
- 1.创建一个可用的NFS Serve(实际存储文件)
- 2.创建Service Account 这是用来管控NFS provisioner在k8s中运行的权限
- 3.创建StorageClass 负责建立PVC并调用NFS provisioner进行预定的工作,并让PV与PVC建立管理
- 4.创建NFS provisioner(制备器)
- 每个 StorageClass 都有一个制备器(Provisioner)用来决定使用哪个卷插件制备 PV。 该字段必须指定。
- 主要有两个功能
- 一个是在NFS共享目录下创建挂载点(volume)
- 另一个则是建了PV并将PV与NFS的挂载点建立关联
常见的存储制备器
可以运行和指定外部制备器,这些独立的程序遵循由 Kubernetes 定义的 规范。 外部供应商的作者完全可以自由决定他们的代码保存于何处、打包方式、运行方式、使用的插件(包括 Flex)等。
代码仓库 kubernetes-sigs/sig-storage-lib-external-provisioner 包含一个用于为外部制备器编写功能实现的类库。你可以访问代码仓库 kubernetes-sigs/sig-storage-lib-external-provisioner 了解外部驱动列表。
如,NFS 没有内部制备器,可以使用外部制备器。
四、创建StorageClass
1.创建NFS服务器
2.创建Service Account
wget raw.githubusercontent.com/Simontage/k8s/main/StorageClass-demo/rbac.yaml
# 如果网络慢可以直接复制下面的内容
kubectl apply -f rbac.yaml
rbac.yaml (唯一需要修改的地方只有namespace,根据实际情况定义)
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
查看结果
[root@master deploy-demo]# kubectl get sa
NAME SECRETS AGE
default 1 6h30m
nfs-client-provisioner 1 7s
3.创建NFS资源的StorageClass
kubectl apply -f nfs-StorageClass.yaml
nfs-StorageClass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: managed-nfs-storage
namespace: default # 与RBAC文件中的namespace保持一致
provisioner: k8s-nfs-storage # 这里的名称要和provisioner配置文件中的环境变量PROVISIONER_NAME保持一致
# 回收策略
reclaimPolicy: Retain
parameters:
archiveOnDelete: "ture"
# archiveOnDelete: "false"
provisioner的名称要和provisioner配置文件中的环境变量PROVISIONER_NAME保持一致
查看结果
[root@master deploy-demo]# kubectl get StorageClass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
managed-nfs-storage k8s-nfs-storage Delete Immediate false 19s
4.创建NFS provisioner
kubectl apply -f nfs-provisioner.yaml
nfs-provisioner.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default # 与RBAC文件中的namespace保持一致
spec:
replicas: 1
selector:
matchLabels:
app: nfs-client-provisioner
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
image: quay.io/external_storage/nfs-client-provisioner:latest
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-nfs-storage # provisioner名称,请确保该名称与 nfs-StorageClass.yaml文件中的provisioner名称保持一致
- name: NFS_SERVER
value: 192.168.21.223 # NFS Server IP地址
- name: NFS_PATH
value: /middle/nfsdata # NFS挂载卷
volumes:
- name: nfs-client-root
nfs:
server: 192.168.21.223 # NFS Server IP地址
path: /middle/nfsdata # NFS 挂载卷
查看结果
[root@master deploy-demo]# kubectl get deployments.apps,pods
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nfs-client-provisioner 1/1 1 1 3m6s
NAME READY STATUS RESTARTS AGE
pod/nfs-client-provisioner-867b699cb5-nvhmx 1/1 Running 0 3m6s
五、创建Deployment测试
创建
创建pod,申明PVC进行测试
kubectl apply -f demo_nginx_deployment-sc.yaml
demo_nginx_deployment-sc.yaml
# ConfigMap存储nginx配置
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-nginx-configmap
labels:
app: demo-nginx-configmap
data:
nginx.conf: |
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
underscores_in_headers on;
log_format logsjson '{"@timestamp":"$time_iso8601",'
'"server_addr":"$server_addr",'
'"client_ip":"$remote_addr",'
'"http_user_agent":"$http_user_agent",'
'"server_protocol":"$server_protocol",'
'"request_method":"$request_method",'
'"http_host":"$host",'
'"request_uri":"$request_uri",'
'"upstream_addr":"$upstream_addr",'
'"upstream_status":"$upstream_status",'
'"upstream_response_time":"$upstream_response_time",'
'"http_x_forwarded_for":"$http_x_forwarded_for",'
'"http_referer":"$http_referer",'
'"request_time":"$request_time",'
'"request_length":"$request_length",'
'"body_bytes_sent":"$body_bytes_sent",'
'"status":"$status"}';
access_log /var/log/nginx/access.log logsjson;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
server {
client_max_body_size 500M;
listen 80;
location /demo {
add_header X-Server-IP $server_addr;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
return 200 "health check";
}
}
}
---
# 申明一个PVC,指定StorageClass
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: demo-nginx-pvc
spec:
# 指定刚才创建的 storageClassName
storageClassName: "managed-nfs-storage"
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
---
# nginx 服务
apiVersion: v1
kind: Service
metadata:
name: demo-nginx
labels:
app: demo-nginx
spec:
type: NodePort
ports:
# node port 要求端口大于30000
- nodePort: 30013
port: 80
targetPort: 80
protocol: TCP
selector:
app: demo-nginx
---
# nginx 部署 deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-nginx
labels:
app: demo-nginx
spec:
replicas: 1
selector:
matchLabels:
app: demo-nginx
template:
metadata:
labels:
app: demo-nginx
spec:
containers:
- name: demo-nginx
image: docker.io/nginx:1.22.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
requests:
memory: "1Gi"
cpu: "200m"
volumeMounts:
# 日志挂载
- name: nginx-data
mountPath: /var/log/nginx
# 配置挂载
- name: nginx-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
# configmap 挂载配置
- name: nginx-config
configMap:
name: demo-nginx-configmap
items:
- key: nginx.conf
path: nginx.conf
# pvc 挂载日志
- name: nginx-data
persistentVolumeClaim: # 数据卷挂载的是pvc
claimName: demo-nginx-pvc # 与PVC名称保持一致
当执行 kubectl apply -f demo_nginx_deployment-sc.yaml 命令之后, 发现pod一直起不来, 问题原因以及解决方案在后文 问题一
持久化验证
查看共享NFS目录(/middle/nfsdata)是否有生成文件
[root@master ~]# ll /middle/nfsdata
total 4
drwxrwxrwx 2 nfsnobody nfsnobody 4096 Jan 13 23:38 default-demo-nginx-pvc-pvc-eea7dd76-f07d-4895-b1f7-b8bac1cc10e0
# 文件规则是按照${namespace}-${pvcName}-${pvName}创建的
# 目录下正常输出了nginx的日志
[root@master ~]# ll /middle/nfsdata/default-demo-nginx-pvc-pvc-eea7dd76-f07d-4895-b1f7-b8bac1cc10e0/
total 8
-rw-r--r-- 1 nfsnobody nfsnobody 91 Jan 13 23:49 access.log
-rw-r--r-- 1 nfsnobody nfsnobody 632 Jan 13 23:39 error.log
至此Deployment动态使用动态PVC验证结束。
六、 创建Statefulset以及测试
创建
kubectl apply -f demo_nginx_deployment_sc_sts.yaml
demo_nginx_deployment_sc_sts.yaml
# nginx 服务
apiVersion: v1
kind: Service
metadata:
name: demo-nginx-sts
labels:
app: demo-nginx-sts
spec:
type: NodePort
ports:
# node port 要求端口大于30000
- nodePort: 30030
port: 80
targetPort: 80
protocol: TCP
selector:
app: demo-nginx-sts
---
# nginx 无头服务
apiVersion: v1
kind: Service
metadata:
name: demo-nginx-headless
labels:
app: demo-nginx-sts
spec:
clusterIP: None #注意此处的值,None表示无头服务
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
app: demo-nginx-sts
---
# nginx 部署 deployment
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: demo-nginx-sts
labels:
app: demo-nginx-sts
spec:
serviceName: "demo-nginx-sts"
replicas: 2 # 两个副本
selector:
matchLabels:
app: demo-nginx-sts
template:
metadata:
labels:
app: demo-nginx-sts
spec:
containers:
- name: demo-nginx-sts
image: docker.io/nginx:1.22.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
requests:
memory: "1Gi"
cpu: "200m"
volumeMounts:
- mountPath: /var/log/nginx
name: nginx-data-sts
volumeClaimTemplates:
- metadata:
name: nginx-data-sts
#annotations:
# 低版本采用annotations这种方式指定
#volume.beta.kubernetes.io/storage-class: "managed-nfs-storage" #managed-nfs-storage为我们创建的storage-class名称
spec:
storageClassName: managed-nfs-storage # 指定刚才创建的 storageclass
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 1Gi
查看状态
[root@master deploy-demo]# kubectl get pvc,pv,sts,svc,pod
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/demo-nginx-pvc Bound pvc-eea7dd76-f07d-4895-b1f7-b8bac1cc10e0 1Gi RWX managed-nfs-storage 69m
persistentvolumeclaim/k8s-nfs-pv Bound k8s-nfs-pv 50G RWX 4h31m
persistentvolumeclaim/nginx-data-sts-demo-nginx-sts-0 Bound pvc-f343932c-12fc-4f81-90f0-35bc033ac0c2 1Gi RWO managed-nfs-storage 4m42s
persistentvolumeclaim/nginx-data-sts-demo-nginx-sts-1 Bound pvc-10e6f241-e746-49db-b56a-0b53c2407635 1Gi RWO managed-nfs-storage 4m41s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
persistentvolume/k8s-nfs-pv 50G RWX Retain Bound default/k8s-nfs-pv 4h32m
persistentvolume/pvc-10e6f241-e746-49db-b56a-0b53c2407635 1Gi RWO Delete Bound default/nginx-data-sts-demo-nginx-sts-1 managed-nfs-storage 4m41s
persistentvolume/pvc-eea7dd76-f07d-4895-b1f7-b8bac1cc10e0 1Gi RWX Delete Bound default/demo-nginx-pvc managed-nfs-storage 69m
persistentvolume/pvc-f343932c-12fc-4f81-90f0-35bc033ac0c2 1Gi RWO Delete Bound default/nginx-data-sts-demo-nginx-sts-0 managed-nfs-storage 4m42s
NAME READY AGE
statefulset.apps/demo-nginx-sts 2/2 2m40s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/demo-nginx NodePort 10.107.196.123 <none> 80:30013/TCP 8h
service/demo-nginx-headless ClusterIP None <none> 80/TCP 2m40s
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8h
NAME READY STATUS RESTARTS AGE
pod/demo-nginx-6b4f6f75bc-6xwml 1/1 Running 0 47m
pod/demo-nginx-6b4f6f75bc-sbkv5 1/1 Running 0 69m
pod/demo-nginx-sts-0 1/1 Running 0 2m40s
pod/demo-nginx-sts-1 1/1 Running 0 2m39s
pod/nfs-client-provisioner-867b699cb5-nvhmx 1/1 Running 3 (70m ago) 103m
持久化验证
查看共享NFS目录(/middle/nfsdata)是否有生成文件
# 分别生成了 sts-0 、 sts-1
# 文件规则是按照${namespace}-${pvcName}-${pvName}创建的
[root@master deploy-demo]# ll /middle/nfsdata/
total 12
drwxrwxrwx 2 nfsnobody nfsnobody 4096 Jan 14 00:43 default-nginx-data-sts-demo-nginx-sts-0-pvc-f343932c-12fc-4f81-90f0-35bc033ac0c2
drwxrwxrwx 2 nfsnobody nfsnobody 4096 Jan 14 00:43 default-nginx-data-sts-demo-nginx-sts-1-pvc-10e6f241-e746-49db-b56a-0b53c2407635
# 分别 sts-0 、 sts-1 有各自pod的日志记录
# 文件规则是按照${namespace}-${pvcName}-${pvName}创建的
[root@master deploy-demo]# ll /middle/nfsdata/*sts*
/middle/nfsdata/default-nginx-data-sts-demo-nginx-sts-0-pvc-f343932c-12fc-4f81-90f0-35bc033ac0c2:
total 4
-rw-r--r-- 1 nfsnobody nfsnobody 0 Jan 14 00:43 access.log
-rw-r--r-- 1 nfsnobody nfsnobody 2522 Jan 14 00:46 error.log
/middle/nfsdata/default-nginx-data-sts-demo-nginx-sts-1-pvc-10e6f241-e746-49db-b56a-0b53c2407635:
total 4
-rw-r--r-- 1 nfsnobody nfsnobody 0 Jan 14 00:43 access.log
-rw-r--r-- 1 nfsnobody nfsnobody 2319 Jan 14 00:46 error.log
七、关于StorageClass回收策略对数据的影响
1.第一种配置
archiveOnDelete: "false"
reclaimPolicy: Delete #默认没有配置,默认值为Delete
测试结果:
1.pod删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
2.sc删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
3.删除PVC后,PV被删除且NFS Server对应数据被删除
2.第二种配置
archiveOnDelete: "false"
reclaimPolicy: Retain
测试结果:
1.pod删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
2.sc删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
3.删除PVC后,PV不会别删除,且状态由Bound变为Released,NFS Server对应数据被保留
4.重建sc后,新建PVC会绑定新的pv,旧数据可以通过拷贝到新的PV中
3.第三种配置
archiveOnDelete: "ture"
reclaimPolicy: Retain
测试结果:
1.pod删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
2.sc删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
3.删除PVC后,PV不会别删除,且状态由Bound变为Released,NFS Server对应数据被保留
4.重建sc后,新建PVC会绑定新的pv,旧数据可以通过拷贝到新的PV中
4.第四种配置
archiveOnDelete: "ture"
reclaimPolicy: Delete
测试结果:
1.pod删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
2.sc删除重建后数据依然存在,旧pod名称及数据依然保留给新pod使用
3.删除PVC后,PV不会别删除,且状态由Bound变为Released,NFS Server对应数据被保留
4.重建sc后,新建PVC会绑定新的pv,旧数据可以通过拷贝到新的PV中
总结:除以第一种配置外,其他三种配置在PV/PVC被删除后数据依然保留
问题一
在StorageClass使用nfs持久化存储时, 无法动态创建pvc
问题现象
当执行 kubectl apply -f demo_nginx_deployment-sc.yaml 命令之后, 发现 pod 一直起不来, 发现是因为 pod 使用的 demo-nginx-pvc 一直处于Pending, 然后进一步查看状态
[root@master deploy-demo]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
demo-nginx-pvc Pending managed-nfs-storage 26s
k8s-nfs-pv Bound k8s-nfs-pv 50G RWX 3h16m
查看详情描述
[root@master deploy-demo]# kubectl describe pvc demo-nginx-pvc
Name: demo-nginx-pvc
Namespace: default
StorageClass: managed-nfs-storage
Status: Pending
Volume:
Labels: <none>
Annotations: volume.beta.kubernetes.io/storage-provisioner: k8s-nfs-storage
volume.kubernetes.io/storage-provisioner: k8s-nfs-storage
Finalizers: [kubernetes.io/pvc-protection]
Capacity:
Access Modes:
VolumeMode: Filesystem
Used By: demo-nginx-6b4f6f75bc-np7cz
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ExternalProvisioning 5s (x3 over 23s) persistentvolume-controller waiting for a volume to be created, either by external provisioner "k8s-nfs-storage" or manually created by system administrator
问题关键
通过kubectl describe pvc [pvc名称]描述,发现如下错误:waiting for a volume to be created, either by external provisioner "k8s-nfs-storage" or manually created by system administrator.
If volume creation is delayed, please verify that the provisioner is running and correctly registered.
问题原因
在查找资料后发现,在 k8s 1.20 之后,出于对性能和统一 apiserver 调用方式的初衷,k8s 移除了对 SelfLink 的支持,而默认上面指定的 provisioner 版本需要 SelfLink 功能,因此 PVC 无法进行自动制备
。
解决方案一(已验证)
修改kube-apiserver,配置追加 feature-gates=RemoveSelfLink=false
# 修改kube-apiserver的配置
[root@k8sm storage]# cd /etc/kubernetes/manifests
[root@k8sm storage]# vi kube-apiserver.yaml
apiVersion: v1
···
...
- --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
- --feature-gates=RemoveSelfLink=false # 添加这个配置
# 重启kube-apiserver.yaml
[root@k8sm manifests]# kubectl apply -f kube-apiserver.yaml
# 查看状态
# 现在pvc可以正常创建不再Pending, pod 也可以正常运行
[root@master deploy-demo]# kubectl get pods,pvc
NAME READY STATUS RESTARTS AGE
pod/demo-nginx-6b4f6f75bc-sbkv5 1/1 Running 0 5m28s
pod/nfs-client-provisioner-867b699cb5-nvhmx 1/1 Running 3 (6m32s ago) 38m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/demo-nginx-pvc Bound pvc-eea7dd76-f07d-4895-b1f7-b8bac1cc10e0 1Gi RWX managed-nfs-storage 5m28s
persistentvolumeclaim/k8s-nfs-pv Bound k8s-nfs-pv
selfLink 是什么?
selfLink:通过API访问资源自身的URL,例如一个Pod的link可能是/api/v1/namespaces/ns36aa8455/pods/sc-cluster-test-1-6bc58d44d6-r8hld
解决方案二(待验证)
使用其他 nfs-provisioner(存储制备器),不基于 SelfLink 功能的 provisioner 镜像,重新创建 provisioner 容器。
若你能科学上网,可使用这个镜像:
gcr.io/k8s-staging-sig-storage/nfs-subdir-external-provisioner:v4.0.0
国内可使用这个镜像:
registry.cn-beijing.aliyuncs.com/pylixm/nfs-subdir-external-provisioner:v4.0.0
转载请注明出处来源