Notes of "Kubernetes in Actions" - Statefulset
StatefulSet介绍
StatefulSet特点:
- 每个Pod拥有一个唯一确定的身份标识
- StatefulSet确保不会有两个同样标识的pod存在(at-most-one)
- StatefulSet需要每个Pod都创建一个headless Service,用于给pod提供DNS解析,hostname格式为:
<pod-name>.<service-name>.default.svc.cluster.local
Scaling StatefulSet
Scaling down
每次减少StatefulSet的replica数量时,都可以预知哪个pod被减少,例如SS有3个replica,分别为:pod-0
, pod-1
, pod-2
,如果replica减少为2,则首先会删除pod-2
;如果replica减少为1,则继续会删除pod-1
。
Scaling up
扩容依次增加的pod的名称的尾号数字会一次递增。
关联特定的Storage
每个Pod关联一个PVC,PVC的名称也是可预知的,例如Pod名称为pod-0
,则PVC的名称为pvc-0
,pvc的suffix跟pod的suffix一致。
当用户scale down时,StatefulSet只会删除对应的pod,而不会删除pvc,删除动作需要由用户自行执行。
当用户再次执行scale up时,新的Pod又会关联之前的PVC,实现重用PVC和PV。
使用StatefulSet
创建service
apiVersion: v1
kind: Service
metadata:
name: kubia
spec:
clusterIP: None
selector:
app: kubia
ports:
- name: http
port: 80
创建StatefulSet
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: kubia
spec:
# use kubia service for the pod
serviceName: kubia
template:
# pod created by this statefulset will have label app=kubia
metadata:
labels:
app: kubia
spec:
containers:
- name: kubia
image: luksa/kubia-pet
ports:
- name: http
containerPort: 8080
volumeMounts:
- name: data
mountPath: /var/data
# PVC create with this template
volumeClaimTemplates:
- metadata:
name: data
spec:
resources:
requests:
storage: 1Mi
accessModes:
- ReadWriteOnce
访问StatefulSet的pod
k8s允许我们通过API server访问pod,但是每个请求都必须附带一个authorization token
。
<apiServerHost>:<port>/api/v1/namespaces/<namespace>/pods/<pod-name>/proxy/<path>
为了方便开发,k8s提供一个proxy,方便我们直接访问pod
启动proxy (默认端口为8001)
kubectl proxy
现在我们可以直接通过proxy访问pod
curl http://localhost:8001/api/v1/namespaces/default/pods/kubia-0/proxy/
通过NonHeadless Service暴露Stateful pods
apiVersion: v1
kind: Service
metadata:
name: kubia-public
spec:
selector:
app: kubia
ports:
- port: 80
targetPort: 8080
通过api server访问service
<apiServerHost>:<port>/api/v1/namespaces/<namespace>/services/<service-name>/proxy/<path>
StatefulSet中互相发现节点
在StatefulSet中,节点如何其他节点,k8s提供传统的DNS解析方式,也提供一种名为SRV记录的发现方式。
SRV记录
SRV记录是用于查找服务service的hostname和port的记录。
查询srv记录
kubectl run -it srvlookup --image=tutum/dnsutils --rm --restart=Never -- dig SRV kubia.default.svc.cluster.local
在pod的程序中,我们可以通过查询service的srv记录,发现其他peer节点。service的FQDN格式为:
<service>.default.svc.cluster.local
更新statefulset
修改statefulset的manifest yaml,并重新应用该yaml (例如修改image为新的版本)
删除旧的版本
kubectl delete po kubia-0 kubia-1
k8s 1.7版本及以后,StatefulSet支持Deployment的roll out策略 spec.updateStrategy
StatefulSet处理node节点异常
当k8s node节点不可访问后,k8s本身无法得知节点的状态,但是StatefulSet本身需要确保集群中不能重现两个重名的pod,所以需要由管理员告诉k8s,该如何处理。
手工删除unknown状态的pod
当node断开与master的链接后,pod的状态变为unknown
,我们需要手工删除该pod
kubectl delete kubia-0
但执行命令后,该pod并没有被立刻删除。因为API server在等待node节点通知,该pod确实已被删除。但是node已经失联,所以该pod一直在等待删除状态。
强制删除pod
kubectl delete po kubia-0 --force --grace-period 0
当执行完强制删除后,新的pod就会被创建出来。