状态说明
在进行StatefulSet部署之前,我们首先可能要了解一下,什么是"有状态应用"和"无状态应用"。无状态应用就是pod无论部署在哪里,在哪台服务器上提供服务,都是一样的结果,比如经常用的nginx。有状态应用中,最经常用的那就属数据库了,因为数据库一般都是绑定了网络状态和存储状态。特别是主从数据库,哪些是主数据库,哪些是从数据库,都有明显的状态标识。离开标识的这台机器,可能就用不了了。
那在K8S中主要表现的状态有哪些呢,如果抽象成现实应用中,一般就是网络拓扑状态和存储状态。
网络拓扑:这意味着在k8s中运行中的应用对应的各个pod实例,都会有固定的启动顺序,而且不管实例pod销毁后新建,网络标识还是原来的网络标识,其它应用要找到它,还是通过原来的网络标识一样能找到。
存储状态:比如,当数据库实例销毁重建后,我存储的数据还是照样是原来的那份数据。数据库存储的数据是有状态的,是直接和这个应用绑定的,不论你pod实例重建多少次都会取到这份自己的数据。
我们先看看StatefulSet是怎样固定网络拓扑状态的。在网络中一般要标识一个地址,都是通过IP地址或者是域名。但是IP地址是不方便被记忆的,所以用一个域名是非常方便的。在K8S中,通过系统的Service DNS是可以确定一个POD的网络标识的。
固定网络拓扑
我们新建一个Headless的Service和nginx
yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.22.1
ports:
- containerPort: 80
name: web
创建之后发现两个Pod运行,分别为web-0,web-1,IP地址分别是10.244.3.18,10.244.2.20。虽然分配了ip但是ip是动态,唯一固定的是这两个pod的域名和它们创建启动的顺序,先创建web-0,然后是web-1。我们通过<pod-name>.<svc-name>.<namespace>.svc.cluster.local的方式来固定这两个pod的地址。
我们通过web-0.nginx.default.svc.cluster.local和web-1.nginx.default.svc.cluster.local可以在集群内部访问到这两个Pod。我们接下来通过k8s的coredns来解析这两个域名。先找到coredns的ip地址,然后通过dig来解析。
解析后发现pod的域名刚好指向这两个pod的ip地址。我现在删除上面的pod,然后重建,再解析他们的域名,发现ip地址变了,但是域名还是那个域名。
bash
kubectl delete -f teststatefulpod.yaml ; kubectl apply -f teststatefulpod.yaml
固定存储状态
对于应用的存储,这里用pvc来固定应用的存储位置。相对开发人员这里只要熟悉pvc的配置即可,pv的配置一般由运维人员去配置安装。这里我们用分布式存储Rook+Ceph,安装方式可以参考这篇文章<<Centos7.9在K8s安装生产级别的分布式存储Rook+Ceph>>。
我们创建一个带存储的nginx配置
yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
storage: 1Gi
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.22.1
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
storageClassName: rook-ceph-block
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
创建完成后,会出现两个自动创建的pvc,而且是根据pod名创建的。
我们分别对这两个nginx的首页加上特殊标志。
bash
kubectl exec web-0 -- sh -c 'echo hello $(hostname) > /usr/share/nginx/html/index.html'
kubectl exec web-1 -- sh -c 'echo hello $(hostname) > /usr/share/nginx/html/index.html'
然后通过ip分别访问这两个nginx.各自首页分别返回了内容,一个是web-0,一个web-1.
然后删除这两个pod应用,再重建,发现pod虽然重建ip也变了,但是挂载的磁盘还是原来的,内容也没有变。存储状态也是一直保存着的。
bash
kubectl delete -f teststatefulpod.yaml
kubectl apply -f teststatefulpod.yaml