StatefulSet:Pod控制器。
讓客戶滿意是我們工作的目標,不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項目有:申請域名、網(wǎng)站空間、營銷軟件、網(wǎng)站建設(shè)、華容網(wǎng)站維護、網(wǎng)站推廣。
? RC,RS,Deployment,DS。---------->無狀態(tài)的服務(wù)。
? template(模板):根據(jù)模板創(chuàng)建出來的Pod,他們的狀態(tài)都是一模一樣的(除了名稱,IP,域名之外)
? 可以理解為:任何一個Pod,都可以被刪除,然后用新生成的Pod進行替換。
有狀態(tài)的服務(wù):需要記錄前一次或者多次通信中的相關(guān)事件,以作為一下通信的分類標準。比如:MySQL等數(shù)據(jù)庫服務(wù)。(Pod的名稱,不能隨意變化。數(shù)據(jù)持久化的目錄也是不一樣,每一個Pod都有自己獨有的數(shù)據(jù)持久化存儲目錄。)
? mysql:主從關(guān)系。
如果把之前無狀態(tài)的服務(wù)比喻為牛,羊等牲畜。把有狀態(tài)比喻為:寵物。
每一個Pod對應(yīng)一個PVC,每一個PVC對應(yīng)一個PV。
? storageclass:自動創(chuàng)建PV。
? 需要解決:自動創(chuàng)建PVC------------>volumeClaimTemplates
[root@master ~]# vim statefulset.yaml
apiVersion: v1
kind: Service
metadata:
name: headless-svc
labels:
app: headless-svc
spec:
ports:
- port: 80
selector:
app: headless-pod
clusterIP: None
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: statefulset-test
spec:
serviceName: headless-svc
replicas: 3
selector:
matchLabels:
app: headless-pod
template:
metadata:
labels:
app: headless-pod
spec:
containers:
- name: myhttpd
image: httpd
ports:
- containerPort: 80
[root@master ~]# kubectl apply -f statefulset.yaml
service/headless-svc created
statefulset.apps/statefulset-test created
Deployment:Deeployment+RS+隨機字符串(Pod的名稱。)沒有順序的。可以被隨意替代的。
1.headless-svc:無頭服務(wù)。因為沒有IP地址,所以它不具備負載均衡的功能了。因為statefulset要求Pod的名稱是由順序的,每一個Pod都不能被隨意取代,也就是即使Pod重建之后,名稱依然不變。為后端的每一個Pod,去命名。
2.statefulset:定義具體的應(yīng)用
3.volumeClaimTemplates:自動能夠創(chuàng)建PVC,為后端提供專有的存儲。
一、創(chuàng)建StorageClass資源對象。
? 1.基于NFS服務(wù),創(chuàng)建NFS服務(wù)。
[root@master ~]# showmount -e
Export list for master:
/nfsdata *
? 2.創(chuàng)建rbac權(quán)限。
[root@master ~]# mkdir yaml
[root@master ~]# cp rbac-rolebind.yaml yaml/
[root@master ~]# cd yaml/
[root@master yaml]# vim rbac-rolebind.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-provisioner
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nfs-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: ["watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["services", "endpoints"]
verbs: ["get","create","list", "watch","update"]
- apiGroups: ["extensions"]
resources: ["podsecuritypolicies"]
resourceNames: ["nfs-provisioner"]
verbs: ["use"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-provisioner
subjects:
- kind: ServiceAccount
name: nfs-provisioner
roleRef:
kind: ClusterRole
name: nfs-provisioner-runner
apiGroup: rbac.authorization.k8s.io
報錯:
[root@master yaml]# kubectl apply -f rbac-rolebind.yaml
serviceaccount/nfs-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-provisioner-runner unchanged
The ClusterRoleBinding "run-nfs-provisioner" is invalid: subjects[0].namespace: Required value
排錯:
38行添加:
namespace: default
成功:
[root@master yaml]# kubectl apply -f rbac-rolebind.yaml
serviceaccount/nfs-provisioner unchanged
clusterrole.rbac.authorization.k8s.io/nfs-provisioner-runner unchanged
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-provisioner configured
3.創(chuàng)建Deployment資源對象,用Pod代替真正的
[root@master ~]# cp nfs-deployment.yaml yaml/
[root@master ~]# cd yaml/
[root@master yaml]# vim nfs-deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nfs-client-provisioner
spec:
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nfs-client-provisioner
spec:
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccount: nfs-provisioner
containers:
- name: nfs-client-provisioner
image: registry.cn-hangzhou.aliyuncs.com/open-ali/nfs-client-provisioner
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: bdqn
- name: NFS_SERVER
value: 192.168.1.10
- name: NFS_PATH
value: /nfsdata
volumes:
- name: nfs-client-root
nfs:
server: 192.168.1.10
path: /nfsdata
[root@master yaml]# kubectl apply -f nfs-deployment.yaml
deployment.extensions/nfs-client-provisioner created
4.創(chuàng)建storageclass
[root@master ~]# cp test-storageclass.yaml yaml/
[root@master ~]# cd yaml/
[root@master yaml]# vim test-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: sc-nfs
provisioner: bdqn
reclaimPolicy: Retain
刪除之前創(chuàng)建的sc:
[root@master yaml]# kubectl delete sc sc-nfs
storageclass.storage.k8s.io "sc-nfs" deleted
查看有沒有刪除:
[root@master yaml]# kubectl get sc
No resources found.
再次運行文件:
[root@master yaml]# kubectl apply -f test-storageclass.yaml
storageclass.storage.k8s.io/sc-nfs created
二、解決自動創(chuàng)建PVC
先刪除之前創(chuàng)建的statefulset
[root@master yaml]# kubectl delete -f statefulset.yaml
service "headless-svc" deleted
statefulset.apps "statefulset-test" deleted
再修改statefulset.yaml里的文件:
[root@master yaml]# vim statefulset.yaml
apiVersion: v1
kind: Service
metadata:
name: headless-svc
labels:
app: headless-svc
spec:
ports:
- port: 80
name: myweb
selector:
app: headless-pod
clusterIP: None
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: statefulset-test
spec:
serviceName: headless-svc
replicas: 3
selector:
matchLabels:
app: headless-pod
template:
metadata:
labels:
app: headless-pod
spec:
containers:
- image: httpd
name: myhttpd
ports:
- containerPort: 80
name: httpd
volumeMounts:
- mountPath: /mnt
name: test
volumeClaimTemplates:
- metadata:
name: test
annotations: //這是指定storageclass
volume.beta.kubernetes.io/storage-class: sc-nfs
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
生成一下:
[root@master yaml]# kubectl apply -f statefulset.yaml
service/headless-svc created
statefulset.apps/statefulset-test created
驗證是否能被使用:
[root@master yaml]# kubectl exec -it statefulset-test-0 /bin/sh
# cd /mnt
# touch testfile
# exit
[root@master yaml]# ls /nfsdata/default-test-statefulset-test-0-pvc-2fd45b61-6c69-4901-80da-66184e220b6f/
testfile
拓展:
以自己的名稱創(chuàng)建一個名稱空間,以下所有資源都運行在此空間中。用statefuset資源運行一個httpd web服務(wù),要求3個Pod,但是每個Pod的主界面內(nèi)容不一樣,并且都要做專有的數(shù)據(jù)持久化,嘗試刪除其中一個Pod,查看新生成的Pod,總結(jié)對比與之前Deployment資源控制器控制的Pod有什么不同之處?
(一)創(chuàng)建StorageClass資源對象。
注意:nfs服務(wù)要開啟
1、創(chuàng)建namespace的yaml文件
[root@master yaml]# vim namespace.yaml
kind: Namespace
apiVersion: v1
metadata:
name: xgp-lll #namespave的名稱
執(zhí)行一下
[root@master yaml]# kubectl apply -f namespace.yaml
查看一下
[root@master yaml]# kubectl get namespaces
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: nfs-provisioner-runner
namespace: xgp-lll
rules:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-provisioner
subjects:
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: nfs-client-provisioner
namespace: xgp-lll
spec:
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccount: nfs-provisioner
containers:
4、創(chuàng)建storageclass的yaml文件
[root@master yaml]# vim test-storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: stateful-nfs
namespace: xgp-lll
provisioner: xgp #通過provisioner字段關(guān)聯(lián)到上述Deploy
reclaimPolicy: Retain
執(zhí)行一下
[root@master yaml]# kubectl apply -f test-storageclass.yaml
查看一下
[root@master yaml]# kubectl get sc -n xgp-lll
(二)解決自動創(chuàng)建pvc
1、創(chuàng)建statefulset的yaml文件
apiVersion: v1
kind: Service
metadata:
name: headless-svc
namespace: xgp-lll
labels:
app: headless-svc
spec:
ports:
2、 驗證一下數(shù)據(jù)存儲
容器中創(chuàng)建文件
第一個
[root@master yaml]# kubectl exec -it -n xgp-lll statefulset-test-0 /bin/bash
root@statefulset-test-0:/usr/local/apache2# echo 123 > /usr/local/apache2/htdocs/index.html
第二個
[root@master yaml]# kubectl exec -it -n xgp-lll statefulset-test-1 /bin/bash
root@statefulset-test-2:/usr/local/apache2# echo 456 > /usr/local/apache2/htdocs/index.html
第三個
[root@master yaml]# kubectl exec -it -n xgp-lll statefulset-test-2 /bin/bash
root@statefulset-test-1:/usr/local/apache2# echo 789 > /usr/local/apache2/htdocs/index.html
宿主機查看一下
第一個
[root@master yaml]# cat /nfsdata/xgp-lll-test-statefulset-test-0-pvc-ccaa02df-4721-4453-a6ec-4f2c928221d7/index.html
123
第二個
[root@master yaml]# cat /nfsdata/xgp-lll-test-statefulset-test-1-pvc-88e60a58-97ea-4986-91d5-a3a6e907deac/index.html
456
第三個
[root@master yaml]# cat /nfsdata/xgp-lll-test-statefulset-test-2-pvc-4eb2bbe2-63d2-431a-ba3e-b7b8d7e068d3/index.html
789
訪問一下
kubernetes(k8s)StatefulSet 和 Deployment 區(qū)別及選擇方式
訪問方式:
Compare Deployment & StatefulSet
綜上所述:
如果是不需額外數(shù)據(jù)依賴或者狀態(tài)維護的部署,或者replicas是1,優(yōu)先考慮使用Deployment;
如果單純的要做數(shù)據(jù)持久化,防止pod宕掉重啟數(shù)據(jù)丟失,那么使用pv/pvc就可以了;
如果要打通app之間的通信,而又不需要對外暴露,使用headlessService即可;
如果需要使用service的負載均衡,不要使用StatefulSet,盡量使用clusterIP類型,用serviceName做轉(zhuǎn)發(fā);
如果是有多replicas,且需要掛載多個pv且每個pv的數(shù)據(jù)是不同的,因為pod和pv之間是 一 一對應(yīng)的,如果某個pod掛掉再重啟,還需要連接之前的pv,不能連到別的pv上,考慮使用StatefulSet
能不用StatefulSet,就不要用
只能用StatefulSet:
最近在微軟的aks平臺上部署服務(wù),由于Deployment在scale的時候需要動態(tài)申請volume,采取使用volumeClaimTemplates屬性的方式來申請,當(dāng)前Deployment對象(1.15)不支持這一屬性,只有StatefulSet才有,因此不得不使用后者。目前看來有點本末倒置,不過不排除以后k8s會支持這一屬性。
注意:
如果使用StatefulSet,spec.serviceName需要指向headlessServiceName,且不能省略指定步驟,官方文檔要求headlessService必須在創(chuàng)建StatefulSet之前創(chuàng)建完成,經(jīng)過測試,如果沒有也不會影響pod運行(pod還是running狀態(tài)),只是不能擁有一個stable-network-id 集群內(nèi)部不能訪問到這個服務(wù)(如果這個服務(wù)不需要被發(fā)現(xiàn),只需要去發(fā)現(xiàn)其他服務(wù),則serviceName隨便寫一個也行),官方要求要在創(chuàng)建StatefulSet之前創(chuàng)建好headlessService,是為了讓pod啟動時能自動對應(yīng)到service上。
之所以要指定一個headlessService,是因為admin可以給StatefulSet創(chuàng)建多個、多種類型的service,k8s不知道要用哪個service的名稱當(dāng)作集群內(nèi)域名的一部分。
Deployment類型則不能有此參數(shù),否則報錯。