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.9.1
        ports:
        - containerPort: 80
          name: web

# kubectl create -f svc.yaml
# kubectl create -f statefulset.yaml
# kubectl get pods -w -l app=nginx # 查看 StatefulSet 创建两个有状态实例的过程

# 查看pod的IP地址
# kubectl exec 命令进入到容器中查看它们的 hostname
# kubectl exec web-0 -- sh -c 'hostname'
# kubectl exec web-1 -- sh -c 'hostname'
# kubectl run -i --tty --image busybox:1.28.4 dns-test --restart=Never --rm /bin/sh
# nslookup web-0.nginx
# nslookup web-1.nginx

# 把这两个 Pod 删除之后，Kubernetes 会按照原先编号的顺序，创建出了两个新的 Pod
# kubectl delete pod -l app=nginx
# kubectl get pod -w -l app=nginx


# StatefulSet 
# StatefulSet 的核心功能，就是通过某种方式记录这些状态，然后在 Pod 被重新创建时，能够为新 Pod 恢复这些状态。
# 这个控制器的主要作用之一，就是使用 Pod 模板创建 Pod 的时候，对它们进行编号，
# 并且按照编号顺序逐一完成创建工作。而当 StatefulSet 的“控制循环”发现 Pod 的“实际状态”与“期望状态”不一致，
# 需要新建或者删除 Pod 进行“调谐”的时候，它会严格按照这些 Pod 编号的顺序，逐一完成这些操作
#  Headless Service 的方式，StatefulSet 为每个 Pod 创建了一个固定并且稳定的 DNS 记录，来作为它的访问入口

# 拓扑状态。
# 应用的多个实例之间不是完全对等的关系。这些应用实例，必须按照某些顺序启动，比如应用的主节点 A 要先于从节点 B 启动。
# 而如果你把 A 和 B 两个 Pod 删除掉，它们再次被创建出来时也必须严格按照这个顺序才行。
# 并且，新创建出来的 Pod，必须和原来 Pod 的网络标识一样，这样原先的访问者才能使用同样的方法，访问到这个新 Pod。
# 存储状态。
# 应用的多个实例分别绑定了不同的存储数据。对于这些应用实例来说，Pod A 第一次读取到的数据，和隔了十分钟之后再次读取到的数据，应该是同一份，哪怕在此期间 Pod A 被重新创建过。
# 这种情况最典型的例子，就是一个数据库应用的多个存储实例。

# Deployment > StatefulSet > Pod