---
# System prepended metadata

title: '[k8s] StatefulSet'
tags: [workload, kubernetes]

---

[k8s] StatefulSet
==============

> [color=pink]在 K8s 的 Deployment 應用中做了一個假設：發佈應用的 pod 每一個是相同的，沒有相依性、順序性，更無所謂要運行在哪個 K8s node 上。依照需求，可以透過 Deployment 任意進行 pod scale-out scale-in。此可以稱為：無狀態應用（***Stateless Application***）
> > StatefulSet 類似於 Deployment，可以指定要多少個 Pod (replicas)



## replicating stateful applications is more difficult
+ cant be created/deleted at same time
+ cant be randomly addressed
+ replica Pods are not identical: Pod Identity

## Pod Identity
1. sticky identity for each pod
2. created from same spec, but not interchangable
3. persistent identifier across re-scheduling

***for data consistency***
![](https://i.imgur.com/uyv0SPs.png =400x)



### Persistent Volume Claim
+ Stateful 背後會有一個更新內容的儲存空間

在 K8s 中負責管理儲存空間的就是 Volume ，作用跟 Docker 的 Volume 幾乎一模一樣，但畢竟 K8s 的 Volume 只是在 Pod 中做暫時存放的儲存空間而已，當 Pod 移除之後這個儲存空間也會一併消失，為了要在 K8s 中建立一個像資料庫可以永久儲存的空間，也就是這個 Volume 不能被包含在 Pod 內。

*PVC：像是資源需求者*
*PV：像是資源提供者*

## Headless Service
每個 Service 都會有一組自己的 ClusterIP (ExternalName 形式的除外)，所以 Headless 的意思其實就是不要有 ClusterIP，方法也很簡單直接在設定檔裡面加個 ClusterIP: None 即可。

### Architecture
![image](https://hackmd.io/_uploads/ByLkLBC7a.png =400x)

### features of headless service
+ 與其他 Service 不同，沒有 Cluster Service IP
+ 不需要負載平衡
+ 使用 StatefulSet 建立的 Pod 它的名字並不會因為重啟而改變，這時利用這個 DNS record 就能正確地與特定 Pod 連接，不用擔心名字改變、IP 改變
    + ==***<pod name>.<headless-service name>.<namespace>.svc.<cluster-domain>***==
+ 也可以直接接上headless service，還是會發給對應的後端 Pods
    + ==***<headless-service name>.<namespace>.svc.<cluster-domain>***==
    + <font color="red">????</font>但不確定轉發的機制

## use cases
### how to build database cluster

```yaml=
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql-statefulset
spec:
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:8.1
        ports:
        - containerPort: 3306
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: your-root-password
        volumeMounts:
        - name: mysql-vol
          mountPath: /var/lib/mysql
    podManagementPolicy: OrderedReady  
    serviceName: mysql-h
volumeClaimTemplates:
- metadata:
    name: mysql-vol
  spec:
    accessModes: ["ReadWriteOnce"]
    resources:
      requests:
        storage: 1Gi
```
### how to create headless service
```yaml=
apiVersion: v1
kind: Service
metadata:
  name: mysql-h
spec:
  ports:
  - port: 3306
  selector:
    app: mysql
  clusterIP: None
```